2  * Copyright (c) 2000-2007 Apple Inc. All rights reserved. 
   4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. The rights granted to you under the License 
  10  * may not be used to create, or enable the creation or redistribution of, 
  11  * unlawful or unlicensed copies of an Apple operating system, or to 
  12  * circumvent, violate, or enable the circumvention or violation of, any 
  13  * terms of an Apple operating system software license agreement. 
  15  * Please obtain a copy of the License at 
  16  * http://www.opensource.apple.com/apsl/ and read it before using this file. 
  18  * The Original Code and all software distributed under the License are 
  19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  23  * Please see the License for the specific language governing rights and 
  24  * limitations under the License. 
  26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 
  32  * Mach Operating System 
  33  * Copyright (c) 1991,1990,1989 Carnegie Mellon University 
  34  * All Rights Reserved. 
  36  * Permission to use, copy, modify and distribute this software and its 
  37  * documentation is hereby granted, provided that both the copyright 
  38  * notice and this permission notice appear in all copies of the 
  39  * software, derivative works or modified versions, and any portions 
  40  * thereof, and that both notices appear in supporting documentation. 
  42  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 
  43  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 
  44  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 
  46  * Carnegie Mellon requests users of this software to return to 
  48  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU 
  49  *  School of Computer Science 
  50  *  Carnegie Mellon University 
  51  *  Pittsburgh PA 15213-3890 
  53  * any improvements or extensions that they make and grant Carnegie Mellon 
  54  * the rights to redistribute these changes. 
  57  * NOTICE: This file was modified by McAfee Research in 2004 to introduce 
  58  * support for mandatory and extensible security protections.  This notice 
  59  * is included in support of clause 2.2 (b) of the Apple Public License, 
  61  * Copyright (c) 2005 SPARTA, Inc. 
  66  *      File:   ipc/mach_msg.c 
  70  *      Exported message traps.  See mach/message.h. 
  73 #include <mach/mach_types.h> 
  74 #include <mach/kern_return.h> 
  75 #include <mach/port.h> 
  76 #include <mach/message.h> 
  77 #include <mach/mig_errors.h> 
  78 #include <mach/mach_traps.h> 
  80 #include <kern/kern_types.h> 
  81 #include <kern/assert.h> 
  82 #include <kern/cpu_number.h> 
  83 #include <kern/ipc_kobject.h> 
  84 #include <kern/ipc_mig.h> 
  85 #include <kern/task.h> 
  86 #include <kern/thread.h> 
  87 #include <kern/sched_prim.h> 
  88 #include <kern/exception.h> 
  89 #include <kern/misc_protos.h> 
  90 #include <kern/processor.h> 
  91 #include <kern/syscall_subr.h> 
  92 #include <kern/policy_internal.h> 
  93 #include <kern/mach_filter.h> 
  95 #include <vm/vm_map.h> 
  98 #include <ipc/ipc_types.h> 
  99 #include <ipc/ipc_kmsg.h> 
 100 #include <ipc/ipc_mqueue.h> 
 101 #include <ipc/ipc_object.h> 
 102 #include <ipc/ipc_notify.h> 
 103 #include <ipc/ipc_port.h> 
 104 #include <ipc/ipc_pset.h> 
 105 #include <ipc/ipc_space.h> 
 106 #include <ipc/ipc_entry.h> 
 107 #include <ipc/ipc_importance.h> 
 108 #include <ipc/ipc_voucher.h> 
 110 #include <machine/machine_routines.h> 
 111 #include <security/mac_mach_internal.h> 
 113 #include <sys/kdebug.h> 
 116 #define offsetof(type, member)  ((size_t)(&((type *)0)->member)) 
 117 #endif /* offsetof */ 
 120  * Forward declarations - kernel internal routines 
 123 mach_msg_return_t 
mach_msg_send( 
 124         mach_msg_header_t       
*msg
, 
 125         mach_msg_option_t       option
, 
 126         mach_msg_size_t         send_size
, 
 127         mach_msg_timeout_t      send_timeout
, 
 128         mach_port_name_t        notify
); 
 130 mach_msg_return_t 
mach_msg_receive( 
 131         mach_msg_header_t       
*msg
, 
 132         mach_msg_option_t       option
, 
 133         mach_msg_size_t         rcv_size
, 
 134         mach_port_name_t        rcv_name
, 
 135         mach_msg_timeout_t      rcv_timeout
, 
 136         void                    (*continuation
)(mach_msg_return_t
), 
 137         mach_msg_size_t         slist_size
); 
 140 mach_msg_return_t 
msg_receive_error( 
 142         mach_msg_option_t       option
, 
 143         mach_vm_address_t       rcv_addr
, 
 144         mach_msg_size_t         rcv_size
, 
 145         mach_port_seqno_t       seqno
, 
 147         mach_msg_size_t         
*out_size
); 
 149 static mach_msg_return_t
 
 150 mach_msg_rcv_link_special_reply_port( 
 151         ipc_port_t special_reply_port
, 
 152         mach_port_name_t dest_name_port
); 
 155 mach_msg_receive_results_complete(ipc_object_t object
); 
 157 const security_token_t KERNEL_SECURITY_TOKEN 
= KERNEL_SECURITY_TOKEN_VALUE
; 
 158 const audit_token_t KERNEL_AUDIT_TOKEN 
= KERNEL_AUDIT_TOKEN_VALUE
; 
 160 const mach_msg_max_trailer_t trailer_template 
= { 
 161         .msgh_trailer_type 
= MACH_MSG_TRAILER_FORMAT_0
, 
 162         .msgh_trailer_size 
= MACH_MSG_TRAILER_MINIMUM_SIZE
, 
 163         .msgh_sender 
= KERNEL_SECURITY_TOKEN_VALUE
, 
 164         .msgh_audit 
= KERNEL_AUDIT_TOKEN_VALUE
 
 168  *      Routine:        mach_msg_send [Kernel Internal] 
 170  *              Routine for kernel-task threads to send a message. 
 172  *              Unlike mach_msg_send_from_kernel(), this routine 
 173  *              looks port names up in the kernel's port namespace 
 174  *              and copies in the kernel virtual memory (instead 
 175  *              of taking a vm_map_copy_t pointer for OOL descriptors). 
 179  *              MACH_MSG_SUCCESS        Sent the message. 
 180  *              MACH_SEND_MSG_TOO_SMALL Message smaller than a header. 
 181  *              MACH_SEND_NO_BUFFER     Couldn't allocate buffer. 
 182  *              MACH_SEND_INVALID_DATA  Couldn't copy message data. 
 183  *              MACH_SEND_INVALID_HEADER 
 184  *                      Illegal value in the message header bits. 
 185  *              MACH_SEND_INVALID_DEST  The space is dead. 
 186  *              MACH_SEND_INVALID_NOTIFY        Bad notify port. 
 187  *              MACH_SEND_INVALID_DEST  Can't copyin destination port. 
 188  *              MACH_SEND_INVALID_REPLY Can't copyin reply port. 
 189  *              MACH_SEND_TIMED_OUT     Timeout expired without delivery. 
 190  *              MACH_SEND_INTERRUPTED   Delivery interrupted. 
 195         mach_msg_header_t       
*msg
, 
 196         mach_msg_option_t       option
, 
 197         mach_msg_size_t         send_size
, 
 198         mach_msg_timeout_t      send_timeout
, 
 199         mach_msg_priority_t     priority
) 
 201         ipc_space_t space 
= current_space(); 
 202         vm_map_t map 
= current_map(); 
 204         mach_msg_return_t mr
; 
 205         mach_msg_size_t msg_and_trailer_size
; 
 206         mach_msg_max_trailer_t  
*trailer
; 
 208         option 
|= MACH_SEND_KERNEL
; 
 210         if ((send_size 
& 3) || 
 211             send_size 
< sizeof(mach_msg_header_t
) || 
 212             (send_size 
< sizeof(mach_msg_base_t
) && (msg
->msgh_bits 
& MACH_MSGH_BITS_COMPLEX
))) { 
 213                 return MACH_SEND_MSG_TOO_SMALL
; 
 216         if (send_size 
> MACH_MSG_SIZE_MAX 
- MAX_TRAILER_SIZE
) { 
 217                 return MACH_SEND_TOO_LARGE
; 
 220         KDBG(MACHDBG_CODE(DBG_MACH_IPC
, MACH_IPC_KMSG_INFO
) | DBG_FUNC_START
); 
 222         msg_and_trailer_size 
= send_size 
+ MAX_TRAILER_SIZE
; 
 224         kmsg 
= ipc_kmsg_alloc(msg_and_trailer_size
); 
 226         if (kmsg 
== IKM_NULL
) { 
 227                 KDBG(MACHDBG_CODE(DBG_MACH_IPC
, MACH_IPC_KMSG_INFO
) | DBG_FUNC_END
, MACH_SEND_NO_BUFFER
); 
 228                 return MACH_SEND_NO_BUFFER
; 
 231         KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_IPC
, MACH_IPC_KMSG_LINK
) | DBG_FUNC_NONE
, 
 232             (uintptr_t)0,                   /* this should only be called from the kernel! */ 
 233             VM_KERNEL_ADDRPERM((uintptr_t)kmsg
), 
 236         (void) memcpy((void *) kmsg
->ikm_header
, (const void *) msg
, send_size
); 
 238         kmsg
->ikm_header
->msgh_size 
= send_size
; 
 241          * reserve for the trailer the largest space (MAX_TRAILER_SIZE) 
 242          * However, the internal size field of the trailer (msgh_trailer_size) 
 243          * is initialized to the minimum (sizeof(mach_msg_trailer_t)), to optimize 
 244          * the cases where no implicit data is requested. 
 246         trailer 
= (mach_msg_max_trailer_t 
*) ((vm_offset_t
)kmsg
->ikm_header 
+ send_size
); 
 247         bzero(trailer
, sizeof(*trailer
)); 
 248         trailer
->msgh_sender 
= current_thread()->task
->sec_token
; 
 249         trailer
->msgh_audit 
= current_thread()->task
->audit_token
; 
 250         trailer
->msgh_trailer_type 
= MACH_MSG_TRAILER_FORMAT_0
; 
 251         trailer
->msgh_trailer_size 
= MACH_MSG_TRAILER_MINIMUM_SIZE
; 
 253         mr 
= ipc_kmsg_copyin(kmsg
, space
, map
, priority
, &option
); 
 255         if (mr 
!= MACH_MSG_SUCCESS
) { 
 257                 KDBG(MACHDBG_CODE(DBG_MACH_IPC
, MACH_IPC_KMSG_INFO
) | DBG_FUNC_END
, mr
); 
 261         mr 
= ipc_kmsg_send(kmsg
, option
, send_timeout
); 
 263         if (mr 
!= MACH_MSG_SUCCESS
) { 
 264                 mr 
|= ipc_kmsg_copyout_pseudo(kmsg
, space
, map
, MACH_MSG_BODY_NULL
); 
 265                 (void) memcpy((void *) msg
, (const void *) kmsg
->ikm_header
, 
 266                     kmsg
->ikm_header
->msgh_size
); 
 268                 KDBG(MACHDBG_CODE(DBG_MACH_IPC
, MACH_IPC_KMSG_INFO
) | DBG_FUNC_END
, mr
); 
 275  * message header as seen at user-space 
 276  * (for MACH_RCV_LARGE/IDENTITY updating) 
 279         mach_msg_bits_t       msgh_bits
; 
 280         mach_msg_size_t       msgh_size
; 
 281         mach_port_name_t      msgh_remote_port
; 
 282         mach_port_name_t      msgh_local_port
; 
 283         mach_msg_size_t       msgh_reserved
; 
 284         mach_msg_id_t         msgh_id
; 
 285 } mach_msg_user_header_t
; 
 288  *      Routine:        mach_msg_receive_results 
 294  *              MACH_MSG_SUCCESS        Received a message. 
 295  *              MACH_RCV_INVALID_NAME   The name doesn't denote a right, 
 296  *                      or the denoted right is not receive or port set. 
 297  *              MACH_RCV_IN_SET         Receive right is a member of a set. 
 298  *              MACH_RCV_TOO_LARGE      Message wouldn't fit into buffer. 
 299  *              MACH_RCV_TIMED_OUT      Timeout expired without a message. 
 300  *              MACH_RCV_INTERRUPTED    Reception interrupted. 
 301  *              MACH_RCV_PORT_DIED      Port/set died while receiving. 
 302  *              MACH_RCV_PORT_CHANGED   Port moved into set while receiving. 
 303  *              MACH_RCV_INVALID_DATA   Couldn't copy to user buffer. 
 304  *              MACH_RCV_INVALID_NOTIFY Bad notify port. 
 305  *              MACH_RCV_HEADER_ERROR 
 309 mach_msg_receive_results( 
 310         mach_msg_size_t 
*sizep
) 
 312         thread_t          self 
= current_thread(); 
 313         ipc_space_t       space 
= current_space(); 
 314         vm_map_t          map 
= current_map(); 
 316         ipc_object_t      object 
= self
->ith_object
; 
 317         mach_msg_return_t mr 
= self
->ith_state
; 
 318         mach_vm_address_t rcv_addr 
= self
->ith_msg_addr
; 
 319         mach_msg_size_t   rcv_size 
= self
->ith_rsize
; 
 320         mach_msg_option_t option 
= self
->ith_option
; 
 321         ipc_kmsg_t        kmsg 
= self
->ith_kmsg
; 
 322         mach_port_seqno_t seqno 
= self
->ith_seqno
; 
 324         mach_msg_trailer_size_t trailer_size
; 
 325         mach_vm_address_t context
; 
 326         mach_msg_size_t   size 
= 0; 
 329          * unlink the special_reply_port before releasing reference to object. 
 330          * get the thread's turnstile, if the thread donated it's turnstile to the port 
 332         mach_msg_receive_results_complete(object
); 
 335         if (mr 
!= MACH_MSG_SUCCESS
) { 
 336                 if (mr 
== MACH_RCV_TOO_LARGE
) { 
 338                          * If the receive operation occurs with MACH_RCV_LARGE set 
 339                          * then no message was extracted from the queue, and the size 
 340                          * and (optionally) receiver names were the only thing captured. 
 341                          * Just copyout the size (and optional port name) in a fake 
 344                         if (option 
& MACH_RCV_LARGE
) { 
 345                                 if ((option 
& MACH_RCV_STACK
) == 0 && 
 346                                     rcv_size 
>= offsetof(mach_msg_user_header_t
, msgh_reserved
)) { 
 348                                          * We need to inform the user-level code that it needs more 
 349                                          * space.  The value for how much space was returned in the 
 350                                          * msize save area instead of the message (which was left on 
 353                                         if (option 
& MACH_RCV_LARGE_IDENTITY
) { 
 354                                                 if (copyout((char *) &self
->ith_receiver_name
, 
 355                                                     rcv_addr 
+ offsetof(mach_msg_user_header_t
, msgh_local_port
), 
 356                                                     sizeof(mach_port_name_t
))) { 
 357                                                         mr 
= MACH_RCV_INVALID_DATA
; 
 360                                         if (copyout((char *) &self
->ith_msize
, 
 361                                             rcv_addr 
+ offsetof(mach_msg_user_header_t
, msgh_size
), 
 362                                             sizeof(mach_msg_size_t
))) { 
 363                                                 mr 
= MACH_RCV_INVALID_DATA
; 
 367                                 /* discard importance in message */ 
 368                                 ipc_importance_clean(kmsg
); 
 370                                 if (msg_receive_error(kmsg
, option
, rcv_addr
, rcv_size
, seqno
, space
, &size
) 
 371                                     == MACH_RCV_INVALID_DATA
) { 
 372                                         mr 
= MACH_RCV_INVALID_DATA
; 
 383         /* MACH_MSG_SUCCESS */ 
 385 #if IMPORTANCE_INHERITANCE 
 387         /* adopt/transform any importance attributes carried in the message */ 
 388         ipc_importance_receive(kmsg
, option
); 
 390 #endif  /* IMPORTANCE_INHERITANCE */ 
 392         /* auto redeem the voucher in the message */ 
 393         ipc_voucher_receive_postprocessing(kmsg
, option
); 
 395         /* Save destination port context for the trailer before copyout */ 
 396         context 
= kmsg
->ikm_header
->msgh_remote_port
->ip_context
; 
 398         mr 
= ipc_kmsg_copyout(kmsg
, space
, map
, MACH_MSG_BODY_NULL
, option
); 
 400         trailer_size 
= ipc_kmsg_trailer_size(option
, self
); 
 402         if (mr 
!= MACH_MSG_SUCCESS
) { 
 403                 /* already received importance, so have to undo that here */ 
 404                 ipc_importance_unreceive(kmsg
, option
); 
 406                 /* if we had a body error copyout what we have, otherwise a simple header/trailer */ 
 407                 if ((mr 
& ~MACH_MSG_MASK
) == MACH_RCV_BODY_ERROR
) { 
 408                         ipc_kmsg_add_trailer(kmsg
, space
, option
, self
, seqno
, FALSE
, context
); 
 409                         if (ipc_kmsg_put(kmsg
, option
, rcv_addr
, rcv_size
, trailer_size
, &size
) == MACH_RCV_INVALID_DATA
) { 
 410                                 mr 
= MACH_RCV_INVALID_DATA
; 
 413                         if (msg_receive_error(kmsg
, option
, rcv_addr
, rcv_size
, seqno
, space
, &size
) 
 414                             == MACH_RCV_INVALID_DATA
) { 
 415                                 mr 
= MACH_RCV_INVALID_DATA
; 
 419                 /* capture ksmg QoS values to the thread continuation state */ 
 420                 self
->ith_ppriority 
= kmsg
->ikm_ppriority
; 
 421                 self
->ith_qos_override 
= kmsg
->ikm_qos_override
; 
 422                 ipc_kmsg_add_trailer(kmsg
, space
, option
, self
, seqno
, FALSE
, context
); 
 423                 mr 
= ipc_kmsg_put(kmsg
, option
, rcv_addr
, rcv_size
, trailer_size
, &size
); 
 433  *      Routine:        mach_msg_receive [Kernel Internal] 
 435  *              Routine for kernel-task threads to actively receive a message. 
 437  *              Unlike being dispatched to by ipc_kobject_server() or the 
 438  *              reply part of mach_msg_rpc_from_kernel(), this routine 
 439  *              looks up the receive port name in the kernel's port 
 440  *              namespace and copies out received port rights to that namespace 
 441  *              as well.  Out-of-line memory is copied out the kernel's 
 442  *              address space (rather than just providing the vm_map_copy_t). 
 446  *              MACH_MSG_SUCCESS        Received a message. 
 447  *              See <mach/message.h> for list of MACH_RCV_XXX errors. 
 451         mach_msg_header_t       
*msg
, 
 452         mach_msg_option_t       option
, 
 453         mach_msg_size_t         rcv_size
, 
 454         mach_port_name_t        rcv_name
, 
 455         mach_msg_timeout_t      rcv_timeout
, 
 456         void                    (*continuation
)(mach_msg_return_t
), 
 457         __unused mach_msg_size_t slist_size
) 
 459         thread_t self 
= current_thread(); 
 460         ipc_space_t space 
= current_space(); 
 463         mach_msg_return_t mr
; 
 465         mr 
= ipc_mqueue_copyin(space
, rcv_name
, &mqueue
, &object
); 
 466         if (mr 
!= MACH_MSG_SUCCESS
) { 
 469         /* hold ref for object */ 
 471         self
->ith_msg_addr 
= CAST_DOWN(mach_vm_address_t
, msg
); 
 472         self
->ith_object 
= object
; 
 473         self
->ith_rsize 
= rcv_size
; 
 475         self
->ith_option 
= option
; 
 476         self
->ith_continuation 
= continuation
; 
 477         self
->ith_knote 
= ITH_KNOTE_NULL
; 
 479         ipc_mqueue_receive(mqueue
, option
, rcv_size
, rcv_timeout
, THREAD_ABORTSAFE
); 
 480         if ((option 
& MACH_RCV_TIMEOUT
) && rcv_timeout 
== 0) { 
 481                 thread_poll_yield(self
); 
 483         return mach_msg_receive_results(NULL
); 
 487 mach_msg_receive_continue(void) 
 489         mach_msg_return_t mr
; 
 490         thread_t self 
= current_thread(); 
 492         ipc_port_thread_group_unblocked(); 
 493         if (self
->ith_state 
== MACH_PEEK_READY
) { 
 494                 mr 
= MACH_PEEK_READY
; 
 496                 mr 
= mach_msg_receive_results(NULL
); 
 498         (*self
->ith_continuation
)(mr
); 
 503  *      Routine:        mach_msg_overwrite_trap [mach trap] 
 505  *              Possibly send a message; possibly receive a message. 
 509  *              All of mach_msg_send and mach_msg_receive error codes. 
 513 mach_msg_overwrite_trap( 
 514         struct mach_msg_overwrite_trap_args 
*args
) 
 516         mach_vm_address_t       msg_addr 
= args
->msg
; 
 517         mach_msg_option_t       option 
= args
->option
; 
 518         mach_msg_size_t         send_size 
= args
->send_size
; 
 519         mach_msg_size_t         rcv_size 
= args
->rcv_size
; 
 520         mach_port_name_t        rcv_name 
= args
->rcv_name
; 
 521         mach_msg_timeout_t      msg_timeout 
= args
->timeout
; 
 522         mach_msg_priority_t     priority 
= args
->priority
; 
 523         mach_vm_address_t       rcv_msg_addr 
= args
->rcv_msg
; 
 524         __unused mach_port_seqno_t temp_seqno 
= 0; 
 526         mach_msg_return_t  mr 
= MACH_MSG_SUCCESS
; 
 527         vm_map_t map 
= current_map(); 
 529         /* Only accept options allowed by the user */ 
 530         option 
&= MACH_MSG_OPTION_USER
; 
 532         if (option 
& MACH_SEND_MSG
) { 
 533                 ipc_space_t space 
= current_space(); 
 536                 KDBG(MACHDBG_CODE(DBG_MACH_IPC
, MACH_IPC_KMSG_INFO
) | DBG_FUNC_START
); 
 538                 mr 
= ipc_kmsg_get(msg_addr
, send_size
, &kmsg
); 
 540                 if (mr 
!= MACH_MSG_SUCCESS
) { 
 541                         KDBG(MACHDBG_CODE(DBG_MACH_IPC
, MACH_IPC_KMSG_INFO
) | DBG_FUNC_END
, mr
); 
 545                 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_IPC
, MACH_IPC_KMSG_LINK
) | DBG_FUNC_NONE
, 
 547                     VM_KERNEL_ADDRPERM((uintptr_t)kmsg
), 
 551                 mr 
= ipc_kmsg_copyin(kmsg
, space
, map
, priority
, &option
); 
 553                 if (mr 
!= MACH_MSG_SUCCESS
) { 
 555                         KDBG(MACHDBG_CODE(DBG_MACH_IPC
, MACH_IPC_KMSG_INFO
) | DBG_FUNC_END
, mr
); 
 559                 mr 
= ipc_kmsg_send(kmsg
, option
, msg_timeout
); 
 561                 if (mr 
!= MACH_MSG_SUCCESS
) { 
 562                         mr 
|= ipc_kmsg_copyout_pseudo(kmsg
, space
, map
, MACH_MSG_BODY_NULL
); 
 563                         (void) ipc_kmsg_put(kmsg
, option
, msg_addr
, send_size
, 0, NULL
); 
 564                         KDBG(MACHDBG_CODE(DBG_MACH_IPC
, MACH_IPC_KMSG_INFO
) | DBG_FUNC_END
, mr
); 
 569         if (option 
& MACH_RCV_MSG
) { 
 570                 thread_t self 
= current_thread(); 
 571                 ipc_space_t space 
= current_space(); 
 575                 mr 
= ipc_mqueue_copyin(space
, rcv_name
, &mqueue
, &object
); 
 576                 if (mr 
!= MACH_MSG_SUCCESS
) { 
 579                 /* hold ref for object */ 
 581                 if ((option 
& MACH_RCV_SYNC_WAIT
) && !(option 
& MACH_SEND_SYNC_OVERRIDE
)) { 
 582                         ipc_port_t special_reply_port
; 
 583                         special_reply_port 
= ip_object_to_port(object
); 
 584                         /* link the special reply port to the destination */ 
 585                         mr 
= mach_msg_rcv_link_special_reply_port(special_reply_port
, 
 586                             (mach_port_name_t
)priority
); 
 587                         if (mr 
!= MACH_MSG_SUCCESS
) { 
 593                 if (rcv_msg_addr 
!= (mach_vm_address_t
)0) { 
 594                         self
->ith_msg_addr 
= rcv_msg_addr
; 
 596                         self
->ith_msg_addr 
= msg_addr
; 
 598                 self
->ith_object 
= object
; 
 599                 self
->ith_rsize 
= rcv_size
; 
 601                 self
->ith_option 
= option
; 
 602                 self
->ith_receiver_name 
= MACH_PORT_NULL
; 
 603                 self
->ith_continuation 
= thread_syscall_return
; 
 604                 self
->ith_knote 
= ITH_KNOTE_NULL
; 
 606                 ipc_mqueue_receive(mqueue
, option
, rcv_size
, msg_timeout
, THREAD_ABORTSAFE
); 
 607                 if ((option 
& MACH_RCV_TIMEOUT
) && msg_timeout 
== 0) { 
 608                         thread_poll_yield(self
); 
 610                 mr 
= mach_msg_receive_results(NULL
); 
 615         ipc_port_thread_group_unblocked(); 
 620  *      Routine:        mach_msg_rcv_link_special_reply_port 
 622  *              Link the special reply port(rcv right) to the 
 623  *              other end of the sync ipc channel. 
 629 static mach_msg_return_t
 
 630 mach_msg_rcv_link_special_reply_port( 
 631         ipc_port_t special_reply_port
, 
 632         mach_port_name_t dest_name_port
) 
 634         ipc_port_t dest_port 
= IP_NULL
; 
 637         if (current_thread()->ith_special_reply_port 
!= special_reply_port
) { 
 638                 return MACH_RCV_INVALID_NOTIFY
; 
 641         /* Copyin the destination port */ 
 642         if (!MACH_PORT_VALID(dest_name_port
)) { 
 643                 return MACH_RCV_INVALID_NOTIFY
; 
 646         kr 
= ipc_port_translate_send(current_space(), dest_name_port
, &dest_port
); 
 647         if (kr 
== KERN_SUCCESS
) { 
 648                 ip_reference(dest_port
); 
 649                 ip_unlock(dest_port
); 
 652                  * The receive right of dest port might have gone away, 
 653                  * do not fail the receive in that case. 
 655                 ipc_port_link_special_reply_port(special_reply_port
, 
 658                 ip_release(dest_port
); 
 660         return MACH_MSG_SUCCESS
; 
 664  *      Routine:        mach_msg_receive_results_complete 
 666  *              Get thread's turnstile back from the object and 
 667  *              if object is a special reply port then reset its 
 675 mach_msg_receive_results_complete(ipc_object_t object
) 
 677         thread_t self 
= current_thread(); 
 678         ipc_port_t port 
= IPC_PORT_NULL
; 
 679         boolean_t get_turnstile 
= (self
->turnstile 
== TURNSTILE_NULL
); 
 681         if (io_otype(object
) == IOT_PORT
) { 
 682                 port 
= ip_object_to_port(object
); 
 684                 assert(self
->turnstile 
!= TURNSTILE_NULL
); 
 688         uint8_t flags 
= IPC_PORT_ADJUST_SR_ALLOW_SYNC_LINKAGE
; 
 691          * Don't clear the ip_srp_msg_sent bit if... 
 693         if (!((self
->ith_state 
== MACH_RCV_TOO_LARGE 
&& self
->ith_option 
& MACH_RCV_LARGE
) || //msg was too large and the next receive will get it 
 694             self
->ith_state 
== MACH_RCV_INTERRUPTED 
|| 
 695             self
->ith_state 
== MACH_RCV_TIMED_OUT 
|| 
 696             self
->ith_state 
== MACH_RCV_PORT_CHANGED 
|| 
 697             self
->ith_state 
== MACH_PEEK_READY
)) { 
 698                 flags 
|= IPC_PORT_ADJUST_SR_RECEIVED_MSG
; 
 701         if (port
->ip_specialreply 
|| get_turnstile
) { 
 703                 ipc_port_adjust_special_reply_port_locked(port
, NULL
, 
 704                     flags
, get_turnstile
); 
 706         assert(self
->turnstile 
!= TURNSTILE_NULL
); 
 707         /* thread now has a turnstile */ 
 711  *      Routine:        mach_msg_trap [mach trap] 
 713  *              Possibly send a message; possibly receive a message. 
 717  *              All of mach_msg_send and mach_msg_receive error codes. 
 722         struct mach_msg_overwrite_trap_args 
*args
) 
 725         args
->rcv_msg 
= (mach_vm_address_t
)0; 
 727         kr 
= mach_msg_overwrite_trap(args
); 
 733  *      Routine:        msg_receive_error       [internal] 
 735  *              Builds a minimal header/trailer and copies it to 
 736  *              the user message buffer.  Invoked when in the case of a 
 737  *              MACH_RCV_TOO_LARGE or MACH_RCV_BODY_ERROR error. 
 740  *              size - maximum buffer size on input, 
 741  *                     actual copied-out size on output 
 743  *              MACH_MSG_SUCCESS        minimal header/trailer copied 
 744  *              MACH_RCV_INVALID_DATA   copyout to user buffer failed 
 750         mach_msg_option_t       option
, 
 751         mach_vm_address_t       rcv_addr
, 
 752         mach_msg_size_t         rcv_size
, 
 753         mach_port_seqno_t       seqno
, 
 755         mach_msg_size_t         
*sizep
) 
 757         mach_vm_address_t       context
; 
 758         mach_msg_trailer_size_t trailer_size
; 
 759         mach_msg_max_trailer_t  
*trailer
; 
 760         thread_t                self 
= current_thread(); 
 762         context 
= kmsg
->ikm_header
->msgh_remote_port
->ip_context
; 
 765          * Copy out the destination port in the message. 
 766          * Destroy all other rights and memory in the message. 
 768         ipc_kmsg_copyout_dest(kmsg
, space
); 
 771          * Build a minimal message with the requested trailer. 
 773         trailer 
= (mach_msg_max_trailer_t 
*) 
 774             ((vm_offset_t
)kmsg
->ikm_header 
+ 
 775             mach_round_msg(sizeof(mach_msg_header_t
))); 
 776         kmsg
->ikm_header
->msgh_size 
= sizeof(mach_msg_header_t
); 
 777         bcopy((const char *)&trailer_template
, 
 779             sizeof(trailer_template
)); 
 781         trailer_size 
= ipc_kmsg_trailer_size(option
, self
); 
 782         ipc_kmsg_add_trailer(kmsg
, space
, option
, self
, 
 783             seqno
, TRUE
, context
); 
 786          * Copy the message to user space and return the size 
 787          * (note that ipc_kmsg_put may also adjust the actual 
 788          * size copied out to user-space). 
 790         if (ipc_kmsg_put(kmsg
, option
, rcv_addr
, rcv_size
, trailer_size
, sizep
) == MACH_RCV_INVALID_DATA
) { 
 791                 return MACH_RCV_INVALID_DATA
; 
 793                 return MACH_MSG_SUCCESS
; 
 797 static SECURITY_READ_ONLY_LATE(mach_msg_fetch_filter_policy_cbfunc_t
) mach_msg_fetch_filter_policy_callback 
= NULL
; 
 800 mach_msg_filter_register_callback( 
 801         const struct mach_msg_filter_callbacks 
*callbacks
) 
 803         if (callbacks 
== NULL
) { 
 804                 return KERN_INVALID_ARGUMENT
; 
 807         if (callbacks
->version 
>= MACH_MSG_FILTER_CALLBACKS_VERSION_0
) { 
 808                 if (mach_msg_fetch_filter_policy_callback 
!= NULL
) { 
 811                 mach_msg_fetch_filter_policy_callback 
= callbacks
->fetch_filter_policy
; 
 817 /* This function should only be called if the task and port allow message filtering */ 
 819 mach_msg_fetch_filter_policy( 
 821         mach_msg_id_t msgh_id
, 
 822         mach_msg_filter_id 
*fid
) 
 824         boolean_t ret 
= TRUE
; 
 826         if (mach_msg_fetch_filter_policy_callback 
== NULL
) { 
 827                 *fid 
= MACH_MSG_FILTER_POLICY_ALLOW
; 
 830         ret 
= mach_msg_fetch_filter_policy_callback(current_task(), port_label
, msgh_id
, fid
);