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 114#ifndef offsetof 115#define offsetof(type, member) ((size_t)(&((type *)0)->member)) 116#endif /* offsetof */ 117 118/* 119 * Forward declarations - kernel internal routines 120 */ 121 122mach_msg_return_t mach_msg_send( 123 mach_msg_header_t *msg, 124 mach_msg_option_t option, 125 mach_msg_size_t send_size, 126 mach_msg_timeout_t send_timeout, 127 mach_port_name_t notify); 128 129mach_msg_return_t mach_msg_receive( 130 mach_msg_header_t *msg, 131 mach_msg_option_t option, 132 mach_msg_size_t rcv_size, 133 mach_port_name_t rcv_name, 134 mach_msg_timeout_t rcv_timeout, 135 void (*continuation)(mach_msg_return_t), 136 mach_msg_size_t slist_size); 137 138 139mach_msg_return_t msg_receive_error( 140 ipc_kmsg_t kmsg, 141 mach_vm_address_t msg_addr, 142 mach_msg_option_t option, 143 mach_port_seqno_t seqno, 144 ipc_space_t space); 145 146security_token_t KERNEL_SECURITY_TOKEN = KERNEL_SECURITY_TOKEN_VALUE; 147audit_token_t KERNEL_AUDIT_TOKEN = KERNEL_AUDIT_TOKEN_VALUE; 148 149mach_msg_format_0_trailer_t trailer_template = { 150 /* mach_msg_trailer_type_t */ MACH_MSG_TRAILER_FORMAT_0, 151 /* mach_msg_trailer_size_t */ MACH_MSG_TRAILER_MINIMUM_SIZE, 152 /* mach_port_seqno_t */ 0, 153 /* security_token_t */ KERNEL_SECURITY_TOKEN_VALUE 154}; 155 156/* 157 * Routine: mach_msg_send 158 * Purpose: 159 * Send a message. 160 * Conditions: 161 * Nothing locked. 162 * Returns: 163 * MACH_MSG_SUCCESS Sent the message. 164 * MACH_SEND_MSG_TOO_SMALL Message smaller than a header. 165 * MACH_SEND_NO_BUFFER Couldn't allocate buffer. 166 * MACH_SEND_INVALID_DATA Couldn't copy message data. 167 * MACH_SEND_INVALID_HEADER 168 * Illegal value in the message header bits. 169 * MACH_SEND_INVALID_DEST The space is dead. 170 * MACH_SEND_INVALID_NOTIFY Bad notify port. 171 * MACH_SEND_INVALID_DEST Can't copyin destination port. 172 * MACH_SEND_INVALID_REPLY Can't copyin reply port. 173 * MACH_SEND_TIMED_OUT Timeout expired without delivery. 174 * MACH_SEND_INTERRUPTED Delivery interrupted. 175 */ 176 177mach_msg_return_t 178mach_msg_send( 179 mach_msg_header_t *msg, 180 mach_msg_option_t option, 181 mach_msg_size_t send_size, 182 mach_msg_timeout_t send_timeout, 183 __unused mach_port_name_t notify) 184{ 185 ipc_space_t space = current_space(); 186 vm_map_t map = current_map(); 187 ipc_kmsg_t kmsg; 188 mach_msg_return_t mr; 189 mach_msg_size_t msg_and_trailer_size; 190 mach_msg_max_trailer_t *trailer; 191 192 if ((send_size < sizeof(mach_msg_header_t)) || (send_size & 3)) 193 return MACH_SEND_MSG_TOO_SMALL; 194 195 if (send_size > MACH_MSG_SIZE_MAX - MAX_TRAILER_SIZE) 196 return MACH_SEND_TOO_LARGE; 197 198 msg_and_trailer_size = send_size + MAX_TRAILER_SIZE; 199 200 kmsg = ipc_kmsg_alloc(msg_and_trailer_size); 201 202 if (kmsg == IKM_NULL) 203 return MACH_SEND_NO_BUFFER; 204 205 (void) memcpy((void *) kmsg->ikm_header, (const void *) msg, send_size); 206 207 kmsg->ikm_header->msgh_size = send_size; 208 209 /* 210 * reserve for the trailer the largest space (MAX_TRAILER_SIZE) 211 * However, the internal size field of the trailer (msgh_trailer_size) 212 * is initialized to the minimum (sizeof(mach_msg_trailer_t)), to optimize 213 * the cases where no implicit data is requested. 214 */ 215 trailer = (mach_msg_max_trailer_t *) ((vm_offset_t)kmsg->ikm_header + send_size); 216 trailer->msgh_sender = current_thread()->task->sec_token; 217 trailer->msgh_audit = current_thread()->task->audit_token; 218 trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0; 219 trailer->msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE; 220 221 mr = ipc_kmsg_copyin(kmsg, space, map, option & MACH_SEND_NOTIFY); 222 if (mr != MACH_MSG_SUCCESS) { 223 ipc_kmsg_free(kmsg); 224 return mr; 225 } 226 227 mr = ipc_kmsg_send(kmsg, option & MACH_SEND_TIMEOUT, send_timeout); 228 if (mr != MACH_MSG_SUCCESS) { 229 mr |= ipc_kmsg_copyout_pseudo(kmsg, space, map, MACH_MSG_BODY_NULL); 230 (void) memcpy((void *) msg, (const void *) kmsg->ikm_header, 231 kmsg->ikm_header->msgh_size); 232 ipc_kmsg_free(kmsg); 233 } 234 235 return mr; 236} 237 238/* 239 * Routine: mach_msg_receive_results 240 * Purpose: 241 * Receive a message. 242 * Conditions: 243 * Nothing locked. 244 * Returns: 245 * MACH_MSG_SUCCESS Received a message. 246 * MACH_RCV_INVALID_NAME The name doesn't denote a right, 247 * or the denoted right is not receive or port set. 248 * MACH_RCV_IN_SET Receive right is a member of a set. 249 * MACH_RCV_TOO_LARGE Message wouldn't fit into buffer. 250 * MACH_RCV_TIMED_OUT Timeout expired without a message. 251 * MACH_RCV_INTERRUPTED Reception interrupted. 252 * MACH_RCV_PORT_DIED Port/set died while receiving. 253 * MACH_RCV_PORT_CHANGED Port moved into set while receiving. 254 * MACH_RCV_INVALID_DATA Couldn't copy to user buffer. 255 * MACH_RCV_INVALID_NOTIFY Bad notify port. 256 * MACH_RCV_HEADER_ERROR 257 */ 258 259mach_msg_return_t 260mach_msg_receive_results(void) 261{ 262 thread_t self = current_thread(); 263 ipc_space_t space = current_space(); 264 vm_map_t map = current_map(); 265 266 ipc_object_t object = self->ith_object; 267 mach_msg_return_t mr = self->ith_state; 268 mach_vm_address_t msg_addr = self->ith_msg_addr; 269 mach_msg_option_t option = self->ith_option; 270 ipc_kmsg_t kmsg = self->ith_kmsg; 271 mach_port_seqno_t seqno = self->ith_seqno; 272 mach_msg_trailer_size_t trailer_size; 273 274 io_release(object); 275 276 if (mr != MACH_MSG_SUCCESS) { 277 278 if (mr == MACH_RCV_TOO_LARGE ) { 279 if (option & MACH_RCV_LARGE) { 280 /* 281 * We need to inform the user-level code that it needs more 282 * space. The value for how much space was returned in the 283 * msize save area instead of the message (which was left on 284 * the queue). 285 */ 286 if (copyout((char *) &self->ith_msize, 287 msg_addr + offsetof(mach_msg_header_t, msgh_size), 288 sizeof(mach_msg_size_t))) 289 mr = MACH_RCV_INVALID_DATA; 290 goto out; 291 } 292 293 if (msg_receive_error(kmsg, msg_addr, option, seqno, space) 294 == MACH_RCV_INVALID_DATA) 295 mr = MACH_RCV_INVALID_DATA; 296 } 297 goto out; 298 } 299 300 trailer_size = ipc_kmsg_add_trailer(kmsg, space, option, self, seqno, FALSE, 301 kmsg->ikm_header->msgh_remote_port->ip_context); 302 /* 303 * If MACH_RCV_OVERWRITE was specified, try to get the scatter 304 * list and verify it against the contents of the message. If 305 * there is any problem with it, we will continue without it as 306 * normal. 307 */ 308 if (option & MACH_RCV_OVERWRITE) { 309 mach_msg_size_t slist_size = self->ith_scatter_list_size; 310 mach_msg_body_t *slist; 311 312 slist = ipc_kmsg_get_scatter(msg_addr, slist_size, kmsg); 313 mr = ipc_kmsg_copyout(kmsg, space, map, slist); 314 ipc_kmsg_free_scatter(slist, slist_size); 315 } else { 316 mr = ipc_kmsg_copyout(kmsg, space, map, MACH_MSG_BODY_NULL); 317 } 318 319 if (mr != MACH_MSG_SUCCESS) { 320 if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) { 321 if (ipc_kmsg_put(msg_addr, kmsg, kmsg->ikm_header->msgh_size + 322 trailer_size) == MACH_RCV_INVALID_DATA) 323 mr = MACH_RCV_INVALID_DATA; 324 } 325 else { 326 if (msg_receive_error(kmsg, msg_addr, option, seqno, space) 327 == MACH_RCV_INVALID_DATA) 328 mr = MACH_RCV_INVALID_DATA; 329 } 330 goto out; 331 } 332 mr = ipc_kmsg_put(msg_addr, 333 kmsg, 334 kmsg->ikm_header->msgh_size + 335 trailer_size); 336 out: 337 return mr; 338} 339 340mach_msg_return_t 341mach_msg_receive( 342 mach_msg_header_t *msg, 343 mach_msg_option_t option, 344 mach_msg_size_t rcv_size, 345 mach_port_name_t rcv_name, 346 mach_msg_timeout_t rcv_timeout, 347 void (*continuation)(mach_msg_return_t), 348 mach_msg_size_t slist_size) 349{ 350 thread_t self = current_thread(); 351 ipc_space_t space = current_space(); 352 ipc_object_t object; 353 ipc_mqueue_t mqueue; 354 mach_msg_return_t mr; 355 356 mr = ipc_mqueue_copyin(space, rcv_name, &mqueue, &object); 357 if (mr != MACH_MSG_SUCCESS) { 358 return mr; 359 } 360 /* hold ref for object */ 361 362 self->ith_msg_addr = CAST_DOWN(mach_vm_address_t, msg); 363 self->ith_object = object; 364 self->ith_msize = rcv_size; 365 self->ith_option = option; 366 self->ith_scatter_list_size = slist_size; 367 self->ith_continuation = continuation; 368 369 ipc_mqueue_receive(mqueue, option, rcv_size, rcv_timeout, THREAD_ABORTSAFE); 370 if ((option & MACH_RCV_TIMEOUT) && rcv_timeout == 0) 371 thread_poll_yield(self); 372 return mach_msg_receive_results(); 373} 374 375void 376mach_msg_receive_continue(void) 377{ 378 thread_t self = current_thread(); 379 380 (*self->ith_continuation)(mach_msg_receive_results()); 381} 382 383 384/* 385 * Routine: mach_msg_overwrite_trap [mach trap] 386 * Purpose: 387 * Possibly send a message; possibly receive a message. 388 * Conditions: 389 * Nothing locked. 390 * Returns: 391 * All of mach_msg_send and mach_msg_receive error codes. 392 */ 393 394mach_msg_return_t 395mach_msg_overwrite_trap( 396 struct mach_msg_overwrite_trap_args *args) 397{ 398 mach_vm_address_t msg_addr = args->msg; 399 mach_msg_option_t option = args->option; 400 mach_msg_size_t send_size = args->send_size; 401 mach_msg_size_t rcv_size = args->rcv_size; 402 mach_port_name_t rcv_name = args->rcv_name; 403 mach_msg_timeout_t msg_timeout = args->timeout; 404 __unused mach_port_name_t notify = args->notify; 405 mach_vm_address_t rcv_msg_addr = args->rcv_msg; 406 mach_msg_size_t scatter_list_size = 0; /* NOT INITIALIZED - but not used in pactice */ 407 __unused mach_port_seqno_t temp_seqno = 0; 408 409 mach_msg_return_t mr = MACH_MSG_SUCCESS; 410 vm_map_t map = current_map(); 411 412 if (option & MACH_SEND_MSG) { 413 ipc_space_t space = current_space(); 414 ipc_kmsg_t kmsg; 415 416 mr = ipc_kmsg_get(msg_addr, send_size, &kmsg); 417 418 if (mr != MACH_MSG_SUCCESS) 419 return mr; 420 421 mr = ipc_kmsg_copyin(kmsg, space, map, option & MACH_SEND_NOTIFY); 422 if (mr != MACH_MSG_SUCCESS) { 423 ipc_kmsg_free(kmsg); 424 return mr; 425 } 426 427 mr = ipc_kmsg_send(kmsg, option & MACH_SEND_TIMEOUT, msg_timeout); 428 429 if (mr != MACH_MSG_SUCCESS) { 430 mr |= ipc_kmsg_copyout_pseudo(kmsg, space, map, MACH_MSG_BODY_NULL); 431 (void) ipc_kmsg_put(msg_addr, kmsg, kmsg->ikm_header->msgh_size); 432 return mr; 433 } 434 } 435 436 if (option & MACH_RCV_MSG) { 437 thread_t self = current_thread(); 438 ipc_space_t space = current_space(); 439 ipc_object_t object; 440 ipc_mqueue_t mqueue; 441 442 mr = ipc_mqueue_copyin(space, rcv_name, &mqueue, &object); 443 if (mr != MACH_MSG_SUCCESS) { 444 return mr; 445 } 446 /* hold ref for object */ 447 448 /* 449 * 1. MACH_RCV_OVERWRITE is on, and rcv_msg is our scatter list 450 * and receive buffer 451 * 2. MACH_RCV_OVERWRITE is off, and rcv_msg might be the 452 * alternate receive buffer (separate send and receive buffers). 453 */ 454 if (option & MACH_RCV_OVERWRITE) 455 self->ith_msg_addr = rcv_msg_addr; 456 else if (rcv_msg_addr != (mach_vm_address_t)0) 457 self->ith_msg_addr = rcv_msg_addr; 458 else 459 self->ith_msg_addr = msg_addr; 460 self->ith_object = object; 461 self->ith_msize = rcv_size; 462 self->ith_option = option; 463 self->ith_scatter_list_size = scatter_list_size; 464 self->ith_receiver_name = MACH_PORT_NULL; 465 self->ith_continuation = thread_syscall_return; 466 467 ipc_mqueue_receive(mqueue, option, rcv_size, msg_timeout, THREAD_ABORTSAFE); 468 if ((option & MACH_RCV_TIMEOUT) && msg_timeout == 0) 469 thread_poll_yield(self); 470 return mach_msg_receive_results(); 471 } 472 473 return MACH_MSG_SUCCESS; 474} 475 476/* 477 * Routine: mach_msg_trap [mach trap] 478 * Purpose: 479 * Possibly send a message; possibly receive a message. 480 * Conditions: 481 * Nothing locked. 482 * Returns: 483 * All of mach_msg_send and mach_msg_receive error codes. 484 */ 485 486mach_msg_return_t 487mach_msg_trap( 488 struct mach_msg_overwrite_trap_args *args) 489{ 490 kern_return_t kr; 491 args->rcv_msg = (mach_vm_address_t)0; 492 493 kr = mach_msg_overwrite_trap(args); 494 return kr; 495} 496 497 498/* 499 * Routine: msg_receive_error [internal] 500 * Purpose: 501 * Builds a minimal header/trailer and copies it to 502 * the user message buffer. Invoked when in the case of a 503 * MACH_RCV_TOO_LARGE or MACH_RCV_BODY_ERROR error. 504 * Conditions: 505 * Nothing locked. 506 * Returns: 507 * MACH_MSG_SUCCESS minimal header/trailer copied 508 * MACH_RCV_INVALID_DATA copyout to user buffer failed 509 */ 510 511mach_msg_return_t 512msg_receive_error( 513 ipc_kmsg_t kmsg, 514 mach_vm_address_t msg_addr, 515 mach_msg_option_t option, 516 mach_port_seqno_t seqno, 517 ipc_space_t space) 518{ 519 mach_vm_address_t context; 520 mach_msg_trailer_size_t trailer_size; 521 mach_msg_max_trailer_t *trailer; 522 523 context = kmsg->ikm_header->msgh_remote_port->ip_context; 524 525 /* 526 * Copy out the destination port in the message. 527 * Destroy all other rights and memory in the message. 528 */ 529 ipc_kmsg_copyout_dest(kmsg, space); 530 531 /* 532 * Build a minimal message with the requested trailer. 533 */ 534 trailer = (mach_msg_max_trailer_t *) 535 ((vm_offset_t)kmsg->ikm_header + 536 round_msg(sizeof(mach_msg_header_t))); 537 kmsg->ikm_header->msgh_size = sizeof(mach_msg_header_t); 538 bcopy( (char *)&trailer_template, 539 (char *)trailer, 540 sizeof(trailer_template)); 541 542 trailer_size = ipc_kmsg_add_trailer(kmsg, space, 543 option, current_thread(), seqno, 544 TRUE, context); 545 546 /* 547 * Copy the message to user space 548 */ 549 if (ipc_kmsg_put(msg_addr, kmsg, kmsg->ikm_header->msgh_size + 550 trailer_size) == MACH_RCV_INVALID_DATA) 551 return(MACH_RCV_INVALID_DATA); 552 else 553 return(MACH_MSG_SUCCESS); 554} 555