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/sched_prim.h> 89#include <kern/exception.h> 90#include <kern/misc_protos.h> 91#include <kern/kalloc.h> 92#include <kern/processor.h> 93#include <kern/syscall_subr.h> 94 95#include <vm/vm_map.h> 96 97#include <ipc/ipc_types.h> 98#include <ipc/ipc_kmsg.h> 99#include <ipc/ipc_mqueue.h> 100#include <ipc/ipc_object.h> 101#include <ipc/ipc_notify.h> 102#include <ipc/ipc_port.h> 103#include <ipc/ipc_pset.h> 104#include <ipc/ipc_space.h> 105#include <ipc/ipc_entry.h> 106#include <ipc/ipc_importance.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 } else { 317 318 /* discard importance in message */ 319 ipc_importance_clean(kmsg); 320 321 if (msg_receive_error(kmsg, msg_addr, option, seqno, space) 322 == MACH_RCV_INVALID_DATA) 323 mr = MACH_RCV_INVALID_DATA; 324 } 325 } 326 return mr; 327 } 328 329#if IMPORTANCE_INHERITANCE 330 331 /* adopt/transform any importance attributes carried in the message */ 332 ipc_importance_receive(kmsg, option); 333 334#endif /* IMPORTANCE_INHERITANCE */ 335 336 trailer_size = ipc_kmsg_add_trailer(kmsg, space, option, self, seqno, FALSE, 337 kmsg->ikm_header->msgh_remote_port->ip_context); 338 /* 339 * If MACH_RCV_OVERWRITE was specified, try to get the scatter 340 * list and verify it against the contents of the message. If 341 * there is any problem with it, we will continue without it as 342 * normal. 343 */ 344 if (option & MACH_RCV_OVERWRITE) { 345 mach_msg_size_t slist_size = self->ith_scatter_list_size; 346 mach_msg_body_t *slist; 347 348 slist = ipc_kmsg_get_scatter(msg_addr, slist_size, kmsg); 349 mr = ipc_kmsg_copyout(kmsg, space, map, slist, option); 350 ipc_kmsg_free_scatter(slist, slist_size); 351 } else { 352 mr = ipc_kmsg_copyout(kmsg, space, map, MACH_MSG_BODY_NULL, option); 353 } 354 355 if (mr != MACH_MSG_SUCCESS) { 356 /* already received importance, so have to undo that here */ 357 ipc_importance_unreceive(kmsg, option); 358 359 if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) { 360 if (ipc_kmsg_put(msg_addr, kmsg, kmsg->ikm_header->msgh_size + 361 trailer_size) == MACH_RCV_INVALID_DATA) 362 mr = MACH_RCV_INVALID_DATA; 363 } 364 else { 365 if (msg_receive_error(kmsg, msg_addr, option, seqno, space) 366 == MACH_RCV_INVALID_DATA) 367 mr = MACH_RCV_INVALID_DATA; 368 } 369 } else { 370 mr = ipc_kmsg_put(msg_addr, 371 kmsg, 372 kmsg->ikm_header->msgh_size + 373 trailer_size); 374 } 375 376 return mr; 377} 378 379/* 380 * Routine: mach_msg_receive [Kernel Internal] 381 * Purpose: 382 * Routine for kernel-task threads to actively receive a message. 383 * 384 * Unlike being dispatched to by ipc_kobject_server() or the 385 * reply part of mach_msg_rpc_from_kernel(), this routine 386 * looks up the receive port name in the kernel's port 387 * namespace and copies out received port rights to that namespace 388 * as well. Out-of-line memory is copied out the kernel's 389 * address space (rather than just providing the vm_map_copy_t). 390 * Conditions: 391 * Nothing locked. 392 * Returns: 393 * MACH_MSG_SUCCESS Received a message. 394 * See <mach/message.h> for list of MACH_RCV_XXX errors. 395 */ 396mach_msg_return_t 397mach_msg_receive( 398 mach_msg_header_t *msg, 399 mach_msg_option_t option, 400 mach_msg_size_t rcv_size, 401 mach_port_name_t rcv_name, 402 mach_msg_timeout_t rcv_timeout, 403 void (*continuation)(mach_msg_return_t), 404 mach_msg_size_t slist_size) 405{ 406 thread_t self = current_thread(); 407 ipc_space_t space = current_space(); 408 ipc_object_t object; 409 ipc_mqueue_t mqueue; 410 mach_msg_return_t mr; 411 412 mr = ipc_mqueue_copyin(space, rcv_name, &mqueue, &object); 413 if (mr != MACH_MSG_SUCCESS) { 414 return mr; 415 } 416 /* hold ref for object */ 417 418 self->ith_msg_addr = CAST_DOWN(mach_vm_address_t, msg); 419 self->ith_object = object; 420 self->ith_msize = rcv_size; 421 self->ith_option = option; 422 self->ith_scatter_list_size = slist_size; 423 self->ith_continuation = continuation; 424 425 ipc_mqueue_receive(mqueue, option, rcv_size, rcv_timeout, THREAD_ABORTSAFE); 426 if ((option & MACH_RCV_TIMEOUT) && rcv_timeout == 0) 427 thread_poll_yield(self); 428 return mach_msg_receive_results(); 429} 430 431void 432mach_msg_receive_continue(void) 433{ 434 thread_t self = current_thread(); 435 436 (*self->ith_continuation)(mach_msg_receive_results()); 437} 438 439 440/* 441 * Routine: mach_msg_overwrite_trap [mach trap] 442 * Purpose: 443 * Possibly send a message; possibly receive a message. 444 * Conditions: 445 * Nothing locked. 446 * Returns: 447 * All of mach_msg_send and mach_msg_receive error codes. 448 */ 449 450mach_msg_return_t 451mach_msg_overwrite_trap( 452 struct mach_msg_overwrite_trap_args *args) 453{ 454 mach_vm_address_t msg_addr = args->msg; 455 mach_msg_option_t option = args->option; 456 mach_msg_size_t send_size = args->send_size; 457 mach_msg_size_t rcv_size = args->rcv_size; 458 mach_port_name_t rcv_name = args->rcv_name; 459 mach_msg_timeout_t msg_timeout = args->timeout; 460 __unused mach_port_name_t notify = args->notify; 461 mach_vm_address_t rcv_msg_addr = args->rcv_msg; 462 mach_msg_size_t scatter_list_size = 0; /* NOT INITIALIZED - but not used in pactice */ 463 __unused mach_port_seqno_t temp_seqno = 0; 464 465 mach_msg_return_t mr = MACH_MSG_SUCCESS; 466 vm_map_t map = current_map(); 467 468 /* Only accept options allowed by the user */ 469 option &= MACH_MSG_OPTION_USER; 470 471 if (option & MACH_SEND_MSG) { 472 ipc_space_t space = current_space(); 473 ipc_kmsg_t kmsg; 474 475 mr = ipc_kmsg_get(msg_addr, send_size, &kmsg); 476 477 if (mr != MACH_MSG_SUCCESS) 478 return mr; 479 480 mr = ipc_kmsg_copyin(kmsg, space, map, &option); 481 482 if (mr != MACH_MSG_SUCCESS) { 483 ipc_kmsg_free(kmsg); 484 return mr; 485 } 486 487 mr = ipc_kmsg_send(kmsg, option, msg_timeout); 488 489 if (mr != MACH_MSG_SUCCESS) { 490 mr |= ipc_kmsg_copyout_pseudo(kmsg, space, map, MACH_MSG_BODY_NULL); 491 (void) ipc_kmsg_put(msg_addr, kmsg, kmsg->ikm_header->msgh_size); 492 return mr; 493 } 494 495 } 496 497 if (option & MACH_RCV_MSG) { 498 thread_t self = current_thread(); 499 ipc_space_t space = current_space(); 500 ipc_object_t object; 501 ipc_mqueue_t mqueue; 502 503 mr = ipc_mqueue_copyin(space, rcv_name, &mqueue, &object); 504 if (mr != MACH_MSG_SUCCESS) { 505 return mr; 506 } 507 /* hold ref for object */ 508 509 /* 510 * 1. MACH_RCV_OVERWRITE is on, and rcv_msg is our scatter list 511 * and receive buffer 512 * 2. MACH_RCV_OVERWRITE is off, and rcv_msg might be the 513 * alternate receive buffer (separate send and receive buffers). 514 */ 515 if (option & MACH_RCV_OVERWRITE) 516 self->ith_msg_addr = rcv_msg_addr; 517 else if (rcv_msg_addr != (mach_vm_address_t)0) 518 self->ith_msg_addr = rcv_msg_addr; 519 else 520 self->ith_msg_addr = msg_addr; 521 self->ith_object = object; 522 self->ith_msize = rcv_size; 523 self->ith_option = option; 524 self->ith_scatter_list_size = scatter_list_size; 525 self->ith_receiver_name = MACH_PORT_NULL; 526 self->ith_continuation = thread_syscall_return; 527 528 ipc_mqueue_receive(mqueue, option, rcv_size, msg_timeout, THREAD_ABORTSAFE); 529 if ((option & MACH_RCV_TIMEOUT) && msg_timeout == 0) 530 thread_poll_yield(self); 531 return mach_msg_receive_results(); 532 } 533 534 return MACH_MSG_SUCCESS; 535} 536 537/* 538 * Routine: mach_msg_trap [mach trap] 539 * Purpose: 540 * Possibly send a message; possibly receive a message. 541 * Conditions: 542 * Nothing locked. 543 * Returns: 544 * All of mach_msg_send and mach_msg_receive error codes. 545 */ 546 547mach_msg_return_t 548mach_msg_trap( 549 struct mach_msg_overwrite_trap_args *args) 550{ 551 kern_return_t kr; 552 args->rcv_msg = (mach_vm_address_t)0; 553 554 kr = mach_msg_overwrite_trap(args); 555 return kr; 556} 557 558 559/* 560 * Routine: msg_receive_error [internal] 561 * Purpose: 562 * Builds a minimal header/trailer and copies it to 563 * the user message buffer. Invoked when in the case of a 564 * MACH_RCV_TOO_LARGE or MACH_RCV_BODY_ERROR error. 565 * Conditions: 566 * Nothing locked. 567 * Returns: 568 * MACH_MSG_SUCCESS minimal header/trailer copied 569 * MACH_RCV_INVALID_DATA copyout to user buffer failed 570 */ 571 572mach_msg_return_t 573msg_receive_error( 574 ipc_kmsg_t kmsg, 575 mach_vm_address_t msg_addr, 576 mach_msg_option_t option, 577 mach_port_seqno_t seqno, 578 ipc_space_t space) 579{ 580 mach_vm_address_t context; 581 mach_msg_trailer_size_t trailer_size; 582 mach_msg_max_trailer_t *trailer; 583 584 context = kmsg->ikm_header->msgh_remote_port->ip_context; 585 586 /* 587 * Copy out the destination port in the message. 588 * Destroy all other rights and memory in the message. 589 */ 590 ipc_kmsg_copyout_dest(kmsg, space); 591 592 /* 593 * Build a minimal message with the requested trailer. 594 */ 595 trailer = (mach_msg_max_trailer_t *) 596 ((vm_offset_t)kmsg->ikm_header + 597 round_msg(sizeof(mach_msg_header_t))); 598 kmsg->ikm_header->msgh_size = sizeof(mach_msg_header_t); 599 bcopy( (char *)&trailer_template, 600 (char *)trailer, 601 sizeof(trailer_template)); 602 603 trailer_size = ipc_kmsg_add_trailer(kmsg, space, 604 option, current_thread(), seqno, 605 TRUE, context); 606 607 /* 608 * Copy the message to user space 609 */ 610 if (ipc_kmsg_put(msg_addr, kmsg, kmsg->ikm_header->msgh_size + 611 trailer_size) == MACH_RCV_INVALID_DATA) 612 return(MACH_RCV_INVALID_DATA); 613 else 614 return(MACH_MSG_SUCCESS); 615} 616