1/* 2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 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. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 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. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* 29 * @OSF_COPYRIGHT@ 30 */ 31/* 32 * Mach Operating System 33 * Copyright (c) 1991,1990,1989 Carnegie Mellon University 34 * All Rights Reserved. 35 * 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. 41 * 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. 45 * 46 * Carnegie Mellon requests users of this software to return to 47 * 48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 49 * School of Computer Science 50 * Carnegie Mellon University 51 * Pittsburgh PA 15213-3890 52 * 53 * any improvements or extensions that they make and grant Carnegie Mellon 54 * the rights to redistribute these changes. 55 */ 56/* 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, 60 * Version 2.0. 61 * Copyright (c) 2005 SPARTA, Inc. 62 */ 63/* 64 */ 65/* 66 * File: ipc/mach_msg.c 67 * Author: Rich Draves 68 * Date: 1989 69 * 70 * Exported message traps. See mach/message.h. 71 */ 72 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> 79 80#include <kern/kern_types.h> 81#include <kern/assert.h> 82#include <kern/counters.h> 83#include <kern/cpu_number.h> 84#include <kern/ipc_kobject.h> 85#include <kern/ipc_mig.h> 86#include <kern/task.h> 87#include <kern/thread.h> 88#include <kern/lock.h> 89#include <kern/sched_prim.h> 90#include <kern/exception.h> 91#include <kern/misc_protos.h> 92#include <kern/kalloc.h> 93#include <kern/processor.h> 94#include <kern/syscall_subr.h> 95 96#include <vm/vm_map.h> 97 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 108#include <machine/machine_routines.h> 109#include <security/mac_mach_internal.h> 110 111#include <sys/kdebug.h> 112 113#ifndef offsetof 114#define offsetof(type, member) ((size_t)(&((type *)0)->member)) 115#endif /* offsetof */ 116 117/* 118 * Forward declarations - kernel internal routines 119 */ 120 121mach_msg_return_t mach_msg_send( 122 mach_msg_header_t *msg, 123 mach_msg_option_t option, 124 mach_msg_size_t send_size, 125 mach_msg_timeout_t send_timeout, 126 mach_port_name_t notify); 127 128mach_msg_return_t mach_msg_receive( 129 mach_msg_header_t *msg, 130 mach_msg_option_t option, 131 mach_msg_size_t rcv_size, 132 mach_port_name_t rcv_name, 133 mach_msg_timeout_t rcv_timeout, 134 void (*continuation)(mach_msg_return_t), 135 mach_msg_size_t slist_size); 136 137 138mach_msg_return_t msg_receive_error( 139 ipc_kmsg_t kmsg, 140 mach_vm_address_t msg_addr, 141 mach_msg_option_t option, 142 mach_port_seqno_t seqno, 143 ipc_space_t space); 144 145security_token_t KERNEL_SECURITY_TOKEN = KERNEL_SECURITY_TOKEN_VALUE; 146audit_token_t KERNEL_AUDIT_TOKEN = KERNEL_AUDIT_TOKEN_VALUE; 147 148mach_msg_format_0_trailer_t trailer_template = { 149 /* mach_msg_trailer_type_t */ MACH_MSG_TRAILER_FORMAT_0, 150 /* mach_msg_trailer_size_t */ MACH_MSG_TRAILER_MINIMUM_SIZE, 151 /* mach_port_seqno_t */ 0, 152 /* security_token_t */ KERNEL_SECURITY_TOKEN_VALUE 153}; 154 155/* 156 * Routine: mach_msg_send [Kernel Internal] 157 * Purpose: 158 * Routine for kernel-task threads to send a message. 159 * 160 * Unlike mach_msg_send_from_kernel(), this routine 161 * looks port names up in the kernel's port namespace 162 * and copies in the kernel virtual memory (instead 163 * of taking a vm_map_copy_t pointer for OOL descriptors). 164 * Conditions: 165 * Nothing locked. 166 * Returns: 167 * MACH_MSG_SUCCESS Sent the message. 168 * MACH_SEND_MSG_TOO_SMALL Message smaller than a header. 169 * MACH_SEND_NO_BUFFER Couldn't allocate buffer. 170 * MACH_SEND_INVALID_DATA Couldn't copy message data. 171 * MACH_SEND_INVALID_HEADER 172 * Illegal value in the message header bits. 173 * MACH_SEND_INVALID_DEST The space is dead. 174 * MACH_SEND_INVALID_NOTIFY Bad notify port. 175 * MACH_SEND_INVALID_DEST Can't copyin destination port. 176 * MACH_SEND_INVALID_REPLY Can't copyin reply port. 177 * MACH_SEND_TIMED_OUT Timeout expired without delivery. 178 * MACH_SEND_INTERRUPTED Delivery interrupted. 179 */ 180 181mach_msg_return_t 182mach_msg_send( 183 mach_msg_header_t *msg, 184 mach_msg_option_t option, 185 mach_msg_size_t send_size, 186 mach_msg_timeout_t send_timeout, 187 __unused mach_port_name_t notify) 188{ 189 ipc_space_t space = current_space(); 190 vm_map_t map = current_map(); 191 ipc_kmsg_t kmsg; 192 mach_msg_return_t mr; 193 mach_msg_size_t msg_and_trailer_size; 194 mach_msg_max_trailer_t *trailer; 195 196 if ((send_size < sizeof(mach_msg_header_t)) || (send_size & 3)) 197 return MACH_SEND_MSG_TOO_SMALL; 198 199 if (send_size > MACH_MSG_SIZE_MAX - MAX_TRAILER_SIZE) 200 return MACH_SEND_TOO_LARGE; 201 202 msg_and_trailer_size = send_size + MAX_TRAILER_SIZE; 203 204 kmsg = ipc_kmsg_alloc(msg_and_trailer_size); 205 206 if (kmsg == IKM_NULL) 207 return MACH_SEND_NO_BUFFER; 208 209 (void) memcpy((void *) kmsg->ikm_header, (const void *) msg, send_size); 210 211 kmsg->ikm_header->msgh_size = send_size; 212 213 /* 214 * reserve for the trailer the largest space (MAX_TRAILER_SIZE) 215 * However, the internal size field of the trailer (msgh_trailer_size) 216 * is initialized to the minimum (sizeof(mach_msg_trailer_t)), to optimize 217 * the cases where no implicit data is requested. 218 */ 219 trailer = (mach_msg_max_trailer_t *) ((vm_offset_t)kmsg->ikm_header + send_size); 220 trailer->msgh_sender = current_thread()->task->sec_token; 221 trailer->msgh_audit = current_thread()->task->audit_token; 222 trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0; 223 trailer->msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE; 224 225 mr = ipc_kmsg_copyin(kmsg, space, map, &option); 226 227 if (mr != MACH_MSG_SUCCESS) { 228 ipc_kmsg_free(kmsg); 229 return mr; 230 } 231 232 mr = ipc_kmsg_send(kmsg, option, send_timeout); 233 234 if (mr != MACH_MSG_SUCCESS) { 235 mr |= ipc_kmsg_copyout_pseudo(kmsg, space, map, MACH_MSG_BODY_NULL); 236 (void) memcpy((void *) msg, (const void *) kmsg->ikm_header, 237 kmsg->ikm_header->msgh_size); 238 ipc_kmsg_free(kmsg); 239 } 240 241 return mr; 242} 243 244/* 245 * message header as seen at user-space 246 * (for MACH_RCV_LARGE/IDENTITY updating) 247 */ 248typedef struct 249{ 250 mach_msg_bits_t msgh_bits; 251 mach_msg_size_t msgh_size; 252 mach_port_name_t msgh_remote_port; 253 mach_port_name_t msgh_local_port; 254 mach_msg_size_t msgh_reserved; 255 mach_msg_id_t msgh_id; 256} mach_msg_user_header_t; 257 258/* 259 * Routine: mach_msg_receive_results 260 * Purpose: 261 * Receive a message. 262 * Conditions: 263 * Nothing locked. 264 * Returns: 265 * MACH_MSG_SUCCESS Received a message. 266 * MACH_RCV_INVALID_NAME The name doesn't denote a right, 267 * or the denoted right is not receive or port set. 268 * MACH_RCV_IN_SET Receive right is a member of a set. 269 * MACH_RCV_TOO_LARGE Message wouldn't fit into buffer. 270 * MACH_RCV_TIMED_OUT Timeout expired without a message. 271 * MACH_RCV_INTERRUPTED Reception interrupted. 272 * MACH_RCV_PORT_DIED Port/set died while receiving. 273 * MACH_RCV_PORT_CHANGED Port moved into set while receiving. 274 * MACH_RCV_INVALID_DATA Couldn't copy to user buffer. 275 * MACH_RCV_INVALID_NOTIFY Bad notify port. 276 * MACH_RCV_HEADER_ERROR 277 */ 278 279mach_msg_return_t 280mach_msg_receive_results(void) 281{ 282 thread_t self = current_thread(); 283 ipc_space_t space = current_space(); 284 vm_map_t map = current_map(); 285 286 ipc_object_t object = self->ith_object; 287 mach_msg_return_t mr = self->ith_state; 288 mach_vm_address_t msg_addr = self->ith_msg_addr; 289 mach_msg_option_t option = self->ith_option; 290 ipc_kmsg_t kmsg = self->ith_kmsg; 291 mach_port_seqno_t seqno = self->ith_seqno; 292 mach_msg_trailer_size_t trailer_size; 293 294 io_release(object); 295 296 if (mr != MACH_MSG_SUCCESS) { 297 298 if (mr == MACH_RCV_TOO_LARGE ) { 299 if (option & MACH_RCV_LARGE) { 300 /* 301 * We need to inform the user-level code that it needs more 302 * space. The value for how much space was returned in the 303 * msize save area instead of the message (which was left on 304 * the queue). 305 */ 306 if (option & MACH_RCV_LARGE_IDENTITY) { 307 if (copyout((char *) &self->ith_receiver_name, 308 msg_addr + offsetof(mach_msg_user_header_t, msgh_local_port), 309 sizeof(mach_port_name_t))) 310 mr = MACH_RCV_INVALID_DATA; 311 } 312 if (copyout((char *) &self->ith_msize, 313 msg_addr + offsetof(mach_msg_user_header_t, msgh_size), 314 sizeof(mach_msg_size_t))) 315 mr = MACH_RCV_INVALID_DATA; 316 goto out; 317 } 318 319 if (msg_receive_error(kmsg, msg_addr, option, seqno, space) 320 == MACH_RCV_INVALID_DATA) 321 mr = MACH_RCV_INVALID_DATA; 322 } 323 goto out; 324 } 325 326#if IMPORTANCE_INHERITANCE 327 if ((kmsg->ikm_header->msgh_bits & MACH_MSGH_BITS_RAISEIMP) != 0) { 328 __unused int impresult; 329 int sender_pid = -1; 330#if IMPORTANCE_DEBUG 331 sender_pid = ((mach_msg_max_trailer_t *) 332 ((vm_offset_t)kmsg->ikm_header + round_msg(kmsg->ikm_header->msgh_size)))->msgh_audit.val[5]; 333#endif /* IMPORTANCE_DEBUG */ 334 ipc_port_t port = kmsg->ikm_header->msgh_remote_port; 335 task_t task_self = current_task(); 336 337 ip_lock(port); 338 assert(port->ip_impcount > 0); 339 port->ip_impcount--; 340 ip_unlock(port); 341 342 if (task_self->imp_receiver == 0) { 343 /* 344 * The task was never ready to receive importance boost, remove msghbit. 345 * This can happen when a receive right (which has donor messages) is copied 346 * out to a non-imp_receiver task (we don't clear the bits on the messages, 347 * but we did't transfer any boost counts either). 348 */ 349 kmsg->ikm_header->msgh_bits &= ~MACH_MSGH_BITS_RAISEIMP; 350 impresult = 0; 351 } else { 352 /* user will accept responsibility for the importance boost */ 353 task_importance_externalize_assertion(task_self, 1, sender_pid); 354 impresult = 1; 355 } 356 357#if IMPORTANCE_DEBUG 358 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, (IMPORTANCE_CODE(IMP_MSG, IMP_MSG_DELV)) | DBG_FUNC_NONE, 359 sender_pid, audit_token_pid_from_task(task_self), 360 kmsg->ikm_header->msgh_id, impresult, 0); 361#endif /* IMPORTANCE_DEBUG */ 362 } 363#endif /* IMPORTANCE_INHERITANCE */ 364 365 trailer_size = ipc_kmsg_add_trailer(kmsg, space, option, self, seqno, FALSE, 366 kmsg->ikm_header->msgh_remote_port->ip_context); 367 /* 368 * If MACH_RCV_OVERWRITE was specified, try to get the scatter 369 * list and verify it against the contents of the message. If 370 * there is any problem with it, we will continue without it as 371 * normal. 372 */ 373 if (option & MACH_RCV_OVERWRITE) { 374 mach_msg_size_t slist_size = self->ith_scatter_list_size; 375 mach_msg_body_t *slist; 376 377 slist = ipc_kmsg_get_scatter(msg_addr, slist_size, kmsg); 378 mr = ipc_kmsg_copyout(kmsg, space, map, slist); 379 ipc_kmsg_free_scatter(slist, slist_size); 380 } else { 381 mr = ipc_kmsg_copyout(kmsg, space, map, MACH_MSG_BODY_NULL); 382 } 383 384 if (mr != MACH_MSG_SUCCESS) { 385 if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) { 386 if (ipc_kmsg_put(msg_addr, kmsg, kmsg->ikm_header->msgh_size + 387 trailer_size) == MACH_RCV_INVALID_DATA) 388 mr = MACH_RCV_INVALID_DATA; 389 } 390 else { 391 if (msg_receive_error(kmsg, msg_addr, option, seqno, space) 392 == MACH_RCV_INVALID_DATA) 393 mr = MACH_RCV_INVALID_DATA; 394 } 395 goto out; 396 } 397 mr = ipc_kmsg_put(msg_addr, 398 kmsg, 399 kmsg->ikm_header->msgh_size + 400 trailer_size); 401 out: 402 return mr; 403} 404 405/* 406 * Routine: mach_msg_receive [Kernel Internal] 407 * Purpose: 408 * Routine for kernel-task threads to actively receive a message. 409 * 410 * Unlike being dispatched to by ipc_kobject_server() or the 411 * reply part of mach_msg_rpc_from_kernel(), this routine 412 * looks up the receive port name in the kernel's port 413 * namespace and copies out received port rights to that namespace 414 * as well. Out-of-line memory is copied out the kernel's 415 * address space (rather than just providing the vm_map_copy_t). 416 * Conditions: 417 * Nothing locked. 418 * Returns: 419 * MACH_MSG_SUCCESS Received a message. 420 * See <mach/message.h> for list of MACH_RCV_XXX errors. 421 */ 422mach_msg_return_t 423mach_msg_receive( 424 mach_msg_header_t *msg, 425 mach_msg_option_t option, 426 mach_msg_size_t rcv_size, 427 mach_port_name_t rcv_name, 428 mach_msg_timeout_t rcv_timeout, 429 void (*continuation)(mach_msg_return_t), 430 mach_msg_size_t slist_size) 431{ 432 thread_t self = current_thread(); 433 ipc_space_t space = current_space(); 434 ipc_object_t object; 435 ipc_mqueue_t mqueue; 436 mach_msg_return_t mr; 437 438 mr = ipc_mqueue_copyin(space, rcv_name, &mqueue, &object); 439 if (mr != MACH_MSG_SUCCESS) { 440 return mr; 441 } 442 /* hold ref for object */ 443 444 self->ith_msg_addr = CAST_DOWN(mach_vm_address_t, msg); 445 self->ith_object = object; 446 self->ith_msize = rcv_size; 447 self->ith_option = option; 448 self->ith_scatter_list_size = slist_size; 449 self->ith_continuation = continuation; 450 451 ipc_mqueue_receive(mqueue, option, rcv_size, rcv_timeout, THREAD_ABORTSAFE); 452 if ((option & MACH_RCV_TIMEOUT) && rcv_timeout == 0) 453 thread_poll_yield(self); 454 return mach_msg_receive_results(); 455} 456 457void 458mach_msg_receive_continue(void) 459{ 460 thread_t self = current_thread(); 461 462 (*self->ith_continuation)(mach_msg_receive_results()); 463} 464 465 466/* 467 * Routine: mach_msg_overwrite_trap [mach trap] 468 * Purpose: 469 * Possibly send a message; possibly receive a message. 470 * Conditions: 471 * Nothing locked. 472 * Returns: 473 * All of mach_msg_send and mach_msg_receive error codes. 474 */ 475 476mach_msg_return_t 477mach_msg_overwrite_trap( 478 struct mach_msg_overwrite_trap_args *args) 479{ 480 mach_vm_address_t msg_addr = args->msg; 481 mach_msg_option_t option = args->option; 482 mach_msg_size_t send_size = args->send_size; 483 mach_msg_size_t rcv_size = args->rcv_size; 484 mach_port_name_t rcv_name = args->rcv_name; 485 mach_msg_timeout_t msg_timeout = args->timeout; 486 __unused mach_port_name_t notify = args->notify; 487 mach_vm_address_t rcv_msg_addr = args->rcv_msg; 488 mach_msg_size_t scatter_list_size = 0; /* NOT INITIALIZED - but not used in pactice */ 489 __unused mach_port_seqno_t temp_seqno = 0; 490 491 mach_msg_return_t mr = MACH_MSG_SUCCESS; 492 vm_map_t map = current_map(); 493 494 /* Only accept options allowed by the user */ 495 option &= MACH_MSG_OPTION_USER; 496 497 if (option & MACH_SEND_MSG) { 498 ipc_space_t space = current_space(); 499 ipc_kmsg_t kmsg; 500 501 mr = ipc_kmsg_get(msg_addr, send_size, &kmsg); 502 503 if (mr != MACH_MSG_SUCCESS) 504 return mr; 505 506 mr = ipc_kmsg_copyin(kmsg, space, map, &option); 507 508 if (mr != MACH_MSG_SUCCESS) { 509 ipc_kmsg_free(kmsg); 510 return mr; 511 } 512 513 mr = ipc_kmsg_send(kmsg, option, msg_timeout); 514 515 if (mr != MACH_MSG_SUCCESS) { 516 mr |= ipc_kmsg_copyout_pseudo(kmsg, space, map, MACH_MSG_BODY_NULL); 517 (void) ipc_kmsg_put(msg_addr, kmsg, kmsg->ikm_header->msgh_size); 518 return mr; 519 } 520 521 } 522 523 if (option & MACH_RCV_MSG) { 524 thread_t self = current_thread(); 525 ipc_space_t space = current_space(); 526 ipc_object_t object; 527 ipc_mqueue_t mqueue; 528 529 mr = ipc_mqueue_copyin(space, rcv_name, &mqueue, &object); 530 if (mr != MACH_MSG_SUCCESS) { 531 return mr; 532 } 533 /* hold ref for object */ 534 535 /* 536 * 1. MACH_RCV_OVERWRITE is on, and rcv_msg is our scatter list 537 * and receive buffer 538 * 2. MACH_RCV_OVERWRITE is off, and rcv_msg might be the 539 * alternate receive buffer (separate send and receive buffers). 540 */ 541 if (option & MACH_RCV_OVERWRITE) 542 self->ith_msg_addr = rcv_msg_addr; 543 else if (rcv_msg_addr != (mach_vm_address_t)0) 544 self->ith_msg_addr = rcv_msg_addr; 545 else 546 self->ith_msg_addr = msg_addr; 547 self->ith_object = object; 548 self->ith_msize = rcv_size; 549 self->ith_option = option; 550 self->ith_scatter_list_size = scatter_list_size; 551 self->ith_receiver_name = MACH_PORT_NULL; 552 self->ith_continuation = thread_syscall_return; 553 554 ipc_mqueue_receive(mqueue, option, rcv_size, msg_timeout, THREAD_ABORTSAFE); 555 if ((option & MACH_RCV_TIMEOUT) && msg_timeout == 0) 556 thread_poll_yield(self); 557 return mach_msg_receive_results(); 558 } 559 560 return MACH_MSG_SUCCESS; 561} 562 563/* 564 * Routine: mach_msg_trap [mach trap] 565 * Purpose: 566 * Possibly send a message; possibly receive a message. 567 * Conditions: 568 * Nothing locked. 569 * Returns: 570 * All of mach_msg_send and mach_msg_receive error codes. 571 */ 572 573mach_msg_return_t 574mach_msg_trap( 575 struct mach_msg_overwrite_trap_args *args) 576{ 577 kern_return_t kr; 578 args->rcv_msg = (mach_vm_address_t)0; 579 580 kr = mach_msg_overwrite_trap(args); 581 return kr; 582} 583 584 585/* 586 * Routine: msg_receive_error [internal] 587 * Purpose: 588 * Builds a minimal header/trailer and copies it to 589 * the user message buffer. Invoked when in the case of a 590 * MACH_RCV_TOO_LARGE or MACH_RCV_BODY_ERROR error. 591 * Conditions: 592 * Nothing locked. 593 * Returns: 594 * MACH_MSG_SUCCESS minimal header/trailer copied 595 * MACH_RCV_INVALID_DATA copyout to user buffer failed 596 */ 597 598mach_msg_return_t 599msg_receive_error( 600 ipc_kmsg_t kmsg, 601 mach_vm_address_t msg_addr, 602 mach_msg_option_t option, 603 mach_port_seqno_t seqno, 604 ipc_space_t space) 605{ 606 mach_vm_address_t context; 607 mach_msg_trailer_size_t trailer_size; 608 mach_msg_max_trailer_t *trailer; 609 610 context = kmsg->ikm_header->msgh_remote_port->ip_context; 611 612 /* 613 * Copy out the destination port in the message. 614 * Destroy all other rights and memory in the message. 615 */ 616 ipc_kmsg_copyout_dest(kmsg, space); 617 618 /* 619 * Build a minimal message with the requested trailer. 620 */ 621 trailer = (mach_msg_max_trailer_t *) 622 ((vm_offset_t)kmsg->ikm_header + 623 round_msg(sizeof(mach_msg_header_t))); 624 kmsg->ikm_header->msgh_size = sizeof(mach_msg_header_t); 625 bcopy( (char *)&trailer_template, 626 (char *)trailer, 627 sizeof(trailer_template)); 628 629 trailer_size = ipc_kmsg_add_trailer(kmsg, space, 630 option, current_thread(), seqno, 631 TRUE, context); 632 633 /* 634 * Copy the message to user space 635 */ 636 if (ipc_kmsg_put(msg_addr, kmsg, kmsg->ikm_header->msgh_size + 637 trailer_size) == MACH_RCV_INVALID_DATA) 638 return(MACH_RCV_INVALID_DATA); 639 else 640 return(MACH_MSG_SUCCESS); 641} 642