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-2006 SPARTA, Inc. 62 */ 63/* 64 */ 65/* 66 * File: ipc/mach_port.c 67 * Author: Rich Draves 68 * Date: 1989 69 * 70 * Exported kernel calls. See mach/mach_port.defs. 71 */ 72 73#include <mach_debug.h> 74#include <mach_rt.h> 75 76#include <mach/port.h> 77#include <mach/kern_return.h> 78#include <mach/notify.h> 79#include <mach/mach_param.h> 80#include <mach/vm_param.h> 81#include <mach/vm_prot.h> 82#include <mach/vm_map.h> 83#include <kern/task.h> 84#include <kern/counters.h> 85#include <kern/thread.h> 86#include <kern/kalloc.h> 87#include <mach/mach_port_server.h> 88#include <vm/vm_map.h> 89#include <vm/vm_kern.h> 90#include <ipc/ipc_entry.h> 91#include <ipc/ipc_space.h> 92#include <ipc/ipc_object.h> 93#include <ipc/ipc_notify.h> 94#include <ipc/ipc_port.h> 95#include <ipc/ipc_pset.h> 96#include <ipc/ipc_right.h> 97#include <ipc/ipc_kmsg.h> 98#include <kern/misc_protos.h> 99#include <security/mac_mach_internal.h> 100 101#if IMPORTANCE_INHERITANCE 102#include <ipc/ipc_importance.h> 103#endif 104 105/* 106 * Forward declarations 107 */ 108void mach_port_names_helper( 109 ipc_port_timestamp_t timestamp, 110 ipc_entry_t entry, 111 mach_port_name_t name, 112 mach_port_name_t *names, 113 mach_port_type_t *types, 114 ipc_entry_num_t *actualp); 115 116void mach_port_gst_helper( 117 ipc_pset_t pset, 118 ipc_entry_num_t maxnames, 119 mach_port_name_t *names, 120 ipc_entry_num_t *actualp); 121 122 123kern_return_t 124mach_port_guard_exception( 125 mach_port_name_t name, 126 uint64_t inguard, 127 uint64_t portguard, 128 unsigned reason); 129 130/* Needs port locked */ 131void mach_port_get_status_helper( 132 ipc_port_t port, 133 mach_port_status_t *status); 134 135/* Zeroed template of qos flags */ 136 137static mach_port_qos_t qos_template; 138 139/* 140 * Routine: mach_port_names_helper 141 * Purpose: 142 * A helper function for mach_port_names. 143 * 144 * Conditions: 145 * Space containing entry is [at least] read-locked. 146 */ 147 148void 149mach_port_names_helper( 150 ipc_port_timestamp_t timestamp, 151 ipc_entry_t entry, 152 mach_port_name_t name, 153 mach_port_name_t *names, 154 mach_port_type_t *types, 155 ipc_entry_num_t *actualp) 156{ 157 ipc_entry_bits_t bits; 158 ipc_port_request_index_t request; 159 mach_port_type_t type = 0; 160 ipc_entry_num_t actual; 161 ipc_port_t port; 162 163 bits = entry->ie_bits; 164 request = entry->ie_request; 165 port = (ipc_port_t) entry->ie_object; 166 167 if (bits & MACH_PORT_TYPE_RECEIVE) { 168 assert(IP_VALID(port)); 169 170 if (request != IE_REQ_NONE) { 171 ip_lock(port); 172 assert(ip_active(port)); 173 type |= ipc_port_request_type(port, name, request); 174 ip_unlock(port); 175 } 176 177 } else if (bits & MACH_PORT_TYPE_SEND_RIGHTS) { 178 mach_port_type_t reqtype; 179 180 assert(IP_VALID(port)); 181 ip_lock(port); 182 183 reqtype = (request != IE_REQ_NONE) ? 184 ipc_port_request_type(port, name, request) : 0; 185 186 /* 187 * If the port is alive, or was alive when the mach_port_names 188 * started, then return that fact. Otherwise, pretend we found 189 * a dead name entry. 190 */ 191 if (ip_active(port) || IP_TIMESTAMP_ORDER(timestamp, port->ip_timestamp)) { 192 type |= reqtype; 193 } else { 194 bits &= ~(IE_BITS_TYPE_MASK); 195 bits |= MACH_PORT_TYPE_DEAD_NAME; 196 /* account for additional reference for dead-name notification */ 197 if (reqtype != 0) 198 bits++; 199 } 200 ip_unlock(port); 201 } 202 203 type |= IE_BITS_TYPE(bits); 204 205 actual = *actualp; 206 names[actual] = name; 207 types[actual] = type; 208 *actualp = actual+1; 209} 210 211/* 212 * Routine: mach_port_names [kernel call] 213 * Purpose: 214 * Retrieves a list of the rights present in the space, 215 * along with type information. (Same as returned 216 * by mach_port_type.) The names are returned in 217 * no particular order, but they (and the type info) 218 * are an accurate snapshot of the space. 219 * Conditions: 220 * Nothing locked. 221 * Returns: 222 * KERN_SUCCESS Arrays of names and types returned. 223 * KERN_INVALID_TASK The space is null. 224 * KERN_INVALID_TASK The space is dead. 225 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. 226 */ 227 228kern_return_t 229mach_port_names( 230 ipc_space_t space, 231 mach_port_name_t **namesp, 232 mach_msg_type_number_t *namesCnt, 233 mach_port_type_t **typesp, 234 mach_msg_type_number_t *typesCnt) 235{ 236 ipc_entry_t table; 237 ipc_entry_num_t tsize; 238 mach_port_index_t index; 239 ipc_entry_num_t actual; /* this many names */ 240 ipc_port_timestamp_t timestamp; /* logical time of this operation */ 241 mach_port_name_t *names; 242 mach_port_type_t *types; 243 kern_return_t kr; 244 245 vm_size_t size; /* size of allocated memory */ 246 vm_offset_t addr1; /* allocated memory, for names */ 247 vm_offset_t addr2; /* allocated memory, for types */ 248 vm_map_copy_t memory1; /* copied-in memory, for names */ 249 vm_map_copy_t memory2; /* copied-in memory, for types */ 250 251 /* safe simplifying assumption */ 252 assert_static(sizeof(mach_port_name_t) == sizeof(mach_port_type_t)); 253 254 if (space == IS_NULL) 255 return KERN_INVALID_TASK; 256 257 size = 0; 258 259 for (;;) { 260 ipc_entry_num_t bound; 261 vm_size_t size_needed; 262 263 is_read_lock(space); 264 if (!is_active(space)) { 265 is_read_unlock(space); 266 if (size != 0) { 267 kmem_free(ipc_kernel_map, addr1, size); 268 kmem_free(ipc_kernel_map, addr2, size); 269 } 270 return KERN_INVALID_TASK; 271 } 272 273 /* upper bound on number of names in the space */ 274 bound = space->is_table_size; 275 size_needed = vm_map_round_page( 276 (bound * sizeof(mach_port_name_t)), 277 VM_MAP_PAGE_MASK(ipc_kernel_map)); 278 279 if (size_needed <= size) 280 break; 281 282 is_read_unlock(space); 283 284 if (size != 0) { 285 kmem_free(ipc_kernel_map, addr1, size); 286 kmem_free(ipc_kernel_map, addr2, size); 287 } 288 size = size_needed; 289 290 kr = vm_allocate(ipc_kernel_map, &addr1, size, VM_FLAGS_ANYWHERE); 291 if (kr != KERN_SUCCESS) 292 return KERN_RESOURCE_SHORTAGE; 293 294 kr = vm_allocate(ipc_kernel_map, &addr2, size, VM_FLAGS_ANYWHERE); 295 if (kr != KERN_SUCCESS) { 296 kmem_free(ipc_kernel_map, addr1, size); 297 return KERN_RESOURCE_SHORTAGE; 298 } 299 300 /* can't fault while we hold locks */ 301 302 kr = vm_map_wire( 303 ipc_kernel_map, 304 vm_map_trunc_page(addr1, 305 VM_MAP_PAGE_MASK(ipc_kernel_map)), 306 vm_map_round_page(addr1 + size, 307 VM_MAP_PAGE_MASK(ipc_kernel_map)), 308 VM_PROT_READ|VM_PROT_WRITE, 309 FALSE); 310 if (kr != KERN_SUCCESS) { 311 kmem_free(ipc_kernel_map, addr1, size); 312 kmem_free(ipc_kernel_map, addr2, size); 313 return KERN_RESOURCE_SHORTAGE; 314 } 315 316 kr = vm_map_wire( 317 ipc_kernel_map, 318 vm_map_trunc_page(addr2, 319 VM_MAP_PAGE_MASK(ipc_kernel_map)), 320 vm_map_round_page(addr2 + size, 321 VM_MAP_PAGE_MASK(ipc_kernel_map)), 322 VM_PROT_READ|VM_PROT_WRITE, 323 FALSE); 324 if (kr != KERN_SUCCESS) { 325 kmem_free(ipc_kernel_map, addr1, size); 326 kmem_free(ipc_kernel_map, addr2, size); 327 return KERN_RESOURCE_SHORTAGE; 328 } 329 330 } 331 /* space is read-locked and active */ 332 333 names = (mach_port_name_t *) addr1; 334 types = (mach_port_type_t *) addr2; 335 actual = 0; 336 337 timestamp = ipc_port_timestamp(); 338 339 table = space->is_table; 340 tsize = space->is_table_size; 341 342 for (index = 0; index < tsize; index++) { 343 ipc_entry_t entry = &table[index]; 344 ipc_entry_bits_t bits = entry->ie_bits; 345 346 if (IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE) { 347 mach_port_name_t name; 348 349 name = MACH_PORT_MAKE(index, IE_BITS_GEN(bits)); 350 mach_port_names_helper(timestamp, entry, name, names, 351 types, &actual); 352 } 353 } 354 355 is_read_unlock(space); 356 357 if (actual == 0) { 358 memory1 = VM_MAP_COPY_NULL; 359 memory2 = VM_MAP_COPY_NULL; 360 361 if (size != 0) { 362 kmem_free(ipc_kernel_map, addr1, size); 363 kmem_free(ipc_kernel_map, addr2, size); 364 } 365 } else { 366 vm_size_t size_used; 367 vm_size_t vm_size_used; 368 369 size_used = actual * sizeof(mach_port_name_t); 370 vm_size_used = 371 vm_map_round_page(size_used, 372 VM_MAP_PAGE_MASK(ipc_kernel_map)); 373 374 /* 375 * Make used memory pageable and get it into 376 * copied-in form. Free any unused memory. 377 */ 378 379 kr = vm_map_unwire( 380 ipc_kernel_map, 381 vm_map_trunc_page(addr1, 382 VM_MAP_PAGE_MASK(ipc_kernel_map)), 383 vm_map_round_page(addr1 + vm_size_used, 384 VM_MAP_PAGE_MASK(ipc_kernel_map)), 385 FALSE); 386 assert(kr == KERN_SUCCESS); 387 388 kr = vm_map_unwire( 389 ipc_kernel_map, 390 vm_map_trunc_page(addr2, 391 VM_MAP_PAGE_MASK(ipc_kernel_map)), 392 vm_map_round_page(addr2 + vm_size_used, 393 VM_MAP_PAGE_MASK(ipc_kernel_map)), 394 FALSE); 395 assert(kr == KERN_SUCCESS); 396 397 kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr1, 398 (vm_map_size_t)size_used, TRUE, &memory1); 399 assert(kr == KERN_SUCCESS); 400 401 kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr2, 402 (vm_map_size_t)size_used, TRUE, &memory2); 403 assert(kr == KERN_SUCCESS); 404 405 if (vm_size_used != size) { 406 kmem_free(ipc_kernel_map, 407 addr1 + vm_size_used, size - vm_size_used); 408 kmem_free(ipc_kernel_map, 409 addr2 + vm_size_used, size - vm_size_used); 410 } 411 } 412 413 *namesp = (mach_port_name_t *) memory1; 414 *namesCnt = actual; 415 *typesp = (mach_port_type_t *) memory2; 416 *typesCnt = actual; 417 return KERN_SUCCESS; 418} 419 420/* 421 * Routine: mach_port_type [kernel call] 422 * Purpose: 423 * Retrieves the type of a right in the space. 424 * The type is a bitwise combination of one or more 425 * of the following type bits: 426 * MACH_PORT_TYPE_SEND 427 * MACH_PORT_TYPE_RECEIVE 428 * MACH_PORT_TYPE_SEND_ONCE 429 * MACH_PORT_TYPE_PORT_SET 430 * MACH_PORT_TYPE_DEAD_NAME 431 * In addition, the following pseudo-type bits may be present: 432 * MACH_PORT_TYPE_DNREQUEST 433 * A dead-name notification is requested. 434 * Conditions: 435 * Nothing locked. 436 * Returns: 437 * KERN_SUCCESS Type is returned. 438 * KERN_INVALID_TASK The space is null. 439 * KERN_INVALID_TASK The space is dead. 440 * KERN_INVALID_NAME The name doesn't denote a right. 441 */ 442 443kern_return_t 444mach_port_type( 445 ipc_space_t space, 446 mach_port_name_t name, 447 mach_port_type_t *typep) 448{ 449 mach_port_urefs_t urefs; 450 ipc_entry_t entry; 451 kern_return_t kr; 452 453 if (space == IS_NULL) 454 return KERN_INVALID_TASK; 455 456 if (name == MACH_PORT_NULL) 457 return KERN_INVALID_NAME; 458 459 if (name == MACH_PORT_DEAD) { 460 *typep = MACH_PORT_TYPE_DEAD_NAME; 461 return KERN_SUCCESS; 462 } 463 464 kr = ipc_right_lookup_write(space, name, &entry); 465 if (kr != KERN_SUCCESS) 466 return kr; 467 468 /* space is write-locked and active */ 469 kr = ipc_right_info(space, name, entry, typep, &urefs); 470 /* space is unlocked */ 471 472#if 1 473 /* JMM - workaround rdar://problem/9121297 (CF being too picky on these bits). */ 474 *typep &= ~(MACH_PORT_TYPE_SPREQUEST | MACH_PORT_TYPE_SPREQUEST_DELAYED); 475#endif 476 477 return kr; 478} 479 480/* 481 * Routine: mach_port_rename [kernel call] 482 * Purpose: 483 * Changes the name denoting a right, 484 * from oname to nname. 485 * Conditions: 486 * Nothing locked. 487 * Returns: 488 * KERN_SUCCESS The right is renamed. 489 * KERN_INVALID_TASK The space is null. 490 * KERN_INVALID_TASK The space is dead. 491 * KERN_INVALID_NAME The oname doesn't denote a right. 492 * KERN_INVALID_VALUE The nname isn't a legal name. 493 * KERN_NAME_EXISTS The nname already denotes a right. 494 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. 495 * 496 * This interface is obsolete and always returns 497 * KERN_NOT_SUPPORTED. 498 */ 499 500kern_return_t 501mach_port_rename( 502 __unused ipc_space_t space, 503 __unused mach_port_name_t oname, 504 __unused mach_port_name_t nname) 505{ 506 return KERN_NOT_SUPPORTED; 507} 508 509 510/* 511 * Routine: mach_port_allocate_name [kernel call] 512 * Purpose: 513 * Allocates a right in a space, using a specific name 514 * for the new right. Possible rights: 515 * MACH_PORT_RIGHT_RECEIVE 516 * MACH_PORT_RIGHT_PORT_SET 517 * MACH_PORT_RIGHT_DEAD_NAME 518 * 519 * A new port (allocated with MACH_PORT_RIGHT_RECEIVE) 520 * has no extant send or send-once rights and no queued 521 * messages. Its queue limit is MACH_PORT_QLIMIT_DEFAULT 522 * and its make-send count is 0. It is not a member of 523 * a port set. It has no registered no-senders or 524 * port-destroyed notification requests. 525 * 526 * A new port set has no members. 527 * 528 * A new dead name has one user reference. 529 * Conditions: 530 * Nothing locked. 531 * Returns: 532 * KERN_SUCCESS The right is allocated. 533 * KERN_INVALID_TASK The space is null. 534 * KERN_INVALID_TASK The space is dead. 535 * KERN_INVALID_VALUE The name isn't a legal name. 536 * KERN_INVALID_VALUE "right" isn't a legal kind of right. 537 * KERN_NAME_EXISTS The name already denotes a right. 538 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. 539 * 540 * Restrictions on name allocation: NT bits are reserved by kernel, 541 * must be set on any chosen name. Can't do this at all in kernel 542 * loaded server. 543 */ 544 545kern_return_t 546mach_port_allocate_name( 547 ipc_space_t space, 548 mach_port_right_t right, 549 mach_port_name_t name) 550{ 551 kern_return_t kr; 552 mach_port_qos_t qos = qos_template; 553 554 qos.name = TRUE; 555 556 if (!MACH_PORT_VALID(name)) 557 return KERN_INVALID_VALUE; 558 559 kr = mach_port_allocate_full (space, right, MACH_PORT_NULL, 560 &qos, &name); 561 return (kr); 562} 563 564/* 565 * Routine: mach_port_allocate [kernel call] 566 * Purpose: 567 * Allocates a right in a space. Like mach_port_allocate_name, 568 * except that the implementation picks a name for the right. 569 * The name may be any legal name in the space that doesn't 570 * currently denote a right. 571 * Conditions: 572 * Nothing locked. 573 * Returns: 574 * KERN_SUCCESS The right is allocated. 575 * KERN_INVALID_TASK The space is null. 576 * KERN_INVALID_TASK The space is dead. 577 * KERN_INVALID_VALUE "right" isn't a legal kind of right. 578 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. 579 * KERN_NO_SPACE No room in space for another right. 580 */ 581 582kern_return_t 583mach_port_allocate( 584 ipc_space_t space, 585 mach_port_right_t right, 586 mach_port_name_t *namep) 587{ 588 kern_return_t kr; 589 mach_port_qos_t qos = qos_template; 590 591 kr = mach_port_allocate_full (space, right, MACH_PORT_NULL, 592 &qos, namep); 593 return (kr); 594} 595 596/* 597 * Routine: mach_port_allocate_qos [kernel call] 598 * Purpose: 599 * Allocates a right, with qos options, in a space. Like 600 * mach_port_allocate_name, except that the implementation 601 * picks a name for the right. The name may be any legal name 602 * in the space that doesn't currently denote a right. 603 * Conditions: 604 * Nothing locked. 605 * Returns: 606 * KERN_SUCCESS The right is allocated. 607 * KERN_INVALID_TASK The space is null. 608 * KERN_INVALID_TASK The space is dead. 609 * KERN_INVALID_VALUE "right" isn't a legal kind of right. 610 * KERN_INVALID_ARGUMENT The qos request was invalid. 611 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. 612 * KERN_NO_SPACE No room in space for another right. 613 */ 614 615kern_return_t 616mach_port_allocate_qos( 617 ipc_space_t space, 618 mach_port_right_t right, 619 mach_port_qos_t *qosp, 620 mach_port_name_t *namep) 621{ 622 kern_return_t kr; 623 624 if (qosp->name) 625 return KERN_INVALID_ARGUMENT; 626 kr = mach_port_allocate_full (space, right, MACH_PORT_NULL, 627 qosp, namep); 628 return (kr); 629} 630 631/* 632 * Routine: mach_port_allocate_full [kernel call] 633 * Purpose: 634 * Allocates a right in a space. Supports all of the 635 * special cases, such as specifying a subsystem, 636 * a specific name, a real-time port, etc. 637 * The name may be any legal name in the space that doesn't 638 * currently denote a right. 639 * Conditions: 640 * Nothing locked. 641 * Returns: 642 * KERN_SUCCESS The right is allocated. 643 * KERN_INVALID_TASK The space is null. 644 * KERN_INVALID_TASK The space is dead. 645 * KERN_INVALID_VALUE "right" isn't a legal kind of right. 646 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. 647 * KERN_NO_SPACE No room in space for another right. 648 */ 649 650kern_return_t 651mach_port_allocate_full( 652 ipc_space_t space, 653 mach_port_right_t right, 654 mach_port_t proto, 655 mach_port_qos_t *qosp, 656 mach_port_name_t *namep) 657{ 658 ipc_kmsg_t kmsg = IKM_NULL; 659 kern_return_t kr; 660 661 if (space == IS_NULL) 662 return (KERN_INVALID_TASK); 663 664 if (proto != MACH_PORT_NULL) 665 return (KERN_INVALID_VALUE); 666 667 if (qosp->name) { 668 if (!MACH_PORT_VALID (*namep)) 669 return (KERN_INVALID_VALUE); 670 } 671 672 if (qosp->prealloc) { 673 if (qosp->len > MACH_MSG_SIZE_MAX - MAX_TRAILER_SIZE) { 674 return KERN_RESOURCE_SHORTAGE; 675 } else { 676 mach_msg_size_t size = qosp->len + MAX_TRAILER_SIZE; 677 678 if (right != MACH_PORT_RIGHT_RECEIVE) 679 return (KERN_INVALID_VALUE); 680 681 kmsg = (ipc_kmsg_t)ipc_kmsg_prealloc(size); 682 if (kmsg == IKM_NULL) 683 return (KERN_RESOURCE_SHORTAGE); 684 } 685 } 686 687 switch (right) { 688 case MACH_PORT_RIGHT_RECEIVE: 689 { 690 ipc_port_t port; 691 692 if (qosp->name) 693 kr = ipc_port_alloc_name(space, *namep, &port); 694 else 695 kr = ipc_port_alloc(space, namep, &port); 696 if (kr == KERN_SUCCESS) { 697 if (kmsg != IKM_NULL) 698 ipc_kmsg_set_prealloc(kmsg, port); 699 700 ip_unlock(port); 701 702 } else if (kmsg != IKM_NULL) 703 ipc_kmsg_free(kmsg); 704 break; 705 } 706 707 case MACH_PORT_RIGHT_PORT_SET: 708 { 709 ipc_pset_t pset; 710 711 if (qosp->name) 712 kr = ipc_pset_alloc_name(space, *namep, &pset); 713 else 714 kr = ipc_pset_alloc(space, namep, &pset); 715 if (kr == KERN_SUCCESS) 716 ips_unlock(pset); 717 break; 718 } 719 720 case MACH_PORT_RIGHT_DEAD_NAME: 721 kr = ipc_object_alloc_dead(space, namep); 722 break; 723 724 default: 725 kr = KERN_INVALID_VALUE; 726 break; 727 } 728 729 return (kr); 730} 731 732/* 733 * Routine: mach_port_destroy [kernel call] 734 * Purpose: 735 * Cleans up and destroys all rights denoted by a name 736 * in a space. The destruction of a receive right 737 * destroys the port, unless a port-destroyed request 738 * has been made for it; the destruction of a port-set right 739 * destroys the port set. 740 * Conditions: 741 * Nothing locked. 742 * Returns: 743 * KERN_SUCCESS The name is destroyed. 744 * KERN_INVALID_TASK The space is null. 745 * KERN_INVALID_TASK The space is dead. 746 * KERN_INVALID_NAME The name doesn't denote a right. 747 */ 748 749kern_return_t 750mach_port_destroy( 751 ipc_space_t space, 752 mach_port_name_t name) 753{ 754 ipc_entry_t entry; 755 kern_return_t kr; 756 757 if (space == IS_NULL) 758 return KERN_INVALID_TASK; 759 760 if (!MACH_PORT_VALID(name)) 761 return KERN_SUCCESS; 762 763 kr = ipc_right_lookup_write(space, name, &entry); 764 if (kr != KERN_SUCCESS) 765 return kr; 766 /* space is write-locked and active */ 767 768 kr = ipc_right_destroy(space, name, entry, TRUE, 0); /* unlocks space */ 769 return kr; 770} 771 772/* 773 * Routine: mach_port_deallocate [kernel call] 774 * Purpose: 775 * Deallocates a user reference from a send right, 776 * send-once right, or a dead-name right. May 777 * deallocate the right, if this is the last uref, 778 * and destroy the name, if it doesn't denote 779 * other rights. 780 * Conditions: 781 * Nothing locked. 782 * Returns: 783 * KERN_SUCCESS The uref is deallocated. 784 * KERN_INVALID_TASK The space is null. 785 * KERN_INVALID_TASK The space is dead. 786 * KERN_INVALID_NAME The name doesn't denote a right. 787 * KERN_INVALID_RIGHT The right isn't correct. 788 */ 789 790kern_return_t 791mach_port_deallocate( 792 ipc_space_t space, 793 mach_port_name_t name) 794{ 795 ipc_entry_t entry; 796 kern_return_t kr; 797 798 if (space == IS_NULL) 799 return KERN_INVALID_TASK; 800 801 if (!MACH_PORT_VALID(name)) 802 return KERN_SUCCESS; 803 804 kr = ipc_right_lookup_write(space, name, &entry); 805 if (kr != KERN_SUCCESS) 806 return kr; 807 /* space is write-locked */ 808 809 kr = ipc_right_dealloc(space, name, entry); /* unlocks space */ 810 return kr; 811} 812 813/* 814 * Routine: mach_port_get_refs [kernel call] 815 * Purpose: 816 * Retrieves the number of user references held by a right. 817 * Receive rights, port-set rights, and send-once rights 818 * always have one user reference. Returns zero if the 819 * name denotes a right, but not the queried right. 820 * Conditions: 821 * Nothing locked. 822 * Returns: 823 * KERN_SUCCESS Number of urefs returned. 824 * KERN_INVALID_TASK The space is null. 825 * KERN_INVALID_TASK The space is dead. 826 * KERN_INVALID_VALUE "right" isn't a legal value. 827 * KERN_INVALID_NAME The name doesn't denote a right. 828 */ 829 830kern_return_t 831mach_port_get_refs( 832 ipc_space_t space, 833 mach_port_name_t name, 834 mach_port_right_t right, 835 mach_port_urefs_t *urefsp) 836{ 837 mach_port_type_t type; 838 mach_port_urefs_t urefs; 839 ipc_entry_t entry; 840 kern_return_t kr; 841 842 if (space == IS_NULL) 843 return KERN_INVALID_TASK; 844 845 if (right >= MACH_PORT_RIGHT_NUMBER) 846 return KERN_INVALID_VALUE; 847 848 if (!MACH_PORT_VALID(name)) { 849 if (right == MACH_PORT_RIGHT_SEND || 850 right == MACH_PORT_RIGHT_SEND_ONCE) { 851 *urefsp = 1; 852 return KERN_SUCCESS; 853 } 854 return KERN_INVALID_NAME; 855 } 856 857 kr = ipc_right_lookup_write(space, name, &entry); 858 if (kr != KERN_SUCCESS) 859 return kr; 860 861 /* space is write-locked and active */ 862 kr = ipc_right_info(space, name, entry, &type, &urefs); 863 /* space is unlocked */ 864 865 if (kr != KERN_SUCCESS) 866 return kr; 867 868 if (type & MACH_PORT_TYPE(right)) 869 switch (right) { 870 case MACH_PORT_RIGHT_SEND_ONCE: 871 assert(urefs == 1); 872 /* fall-through */ 873 874 case MACH_PORT_RIGHT_PORT_SET: 875 case MACH_PORT_RIGHT_RECEIVE: 876 *urefsp = 1; 877 break; 878 879 case MACH_PORT_RIGHT_DEAD_NAME: 880 case MACH_PORT_RIGHT_SEND: 881 assert(urefs > 0); 882 *urefsp = urefs; 883 break; 884 885 default: 886 panic("mach_port_get_refs: strange rights"); 887 } 888 else 889 *urefsp = 0; 890 891 return kr; 892} 893 894/* 895 * Routine: mach_port_mod_refs 896 * Purpose: 897 * Modifies the number of user references held by a right. 898 * The resulting number of user references must be non-negative. 899 * If it is zero, the right is deallocated. If the name 900 * doesn't denote other rights, it is destroyed. 901 * Conditions: 902 * Nothing locked. 903 * Returns: 904 * KERN_SUCCESS Modified number of urefs. 905 * KERN_INVALID_TASK The space is null. 906 * KERN_INVALID_TASK The space is dead. 907 * KERN_INVALID_VALUE "right" isn't a legal value. 908 * KERN_INVALID_NAME The name doesn't denote a right. 909 * KERN_INVALID_RIGHT Name doesn't denote specified right. 910 * KERN_INVALID_VALUE Impossible modification to urefs. 911 * KERN_UREFS_OVERFLOW Urefs would overflow. 912 */ 913 914kern_return_t 915mach_port_mod_refs( 916 ipc_space_t space, 917 mach_port_name_t name, 918 mach_port_right_t right, 919 mach_port_delta_t delta) 920{ 921 ipc_entry_t entry; 922 kern_return_t kr; 923 924 if (space == IS_NULL) 925 return KERN_INVALID_TASK; 926 927 if (right >= MACH_PORT_RIGHT_NUMBER) 928 return KERN_INVALID_VALUE; 929 930 if (!MACH_PORT_VALID(name)) { 931 if (right == MACH_PORT_RIGHT_SEND || 932 right == MACH_PORT_RIGHT_SEND_ONCE) 933 return KERN_SUCCESS; 934 return KERN_INVALID_NAME; 935 } 936 937 kr = ipc_right_lookup_write(space, name, &entry); 938 if (kr != KERN_SUCCESS) 939 return kr; 940 /* space is write-locked and active */ 941 942 kr = ipc_right_delta(space, name, entry, right, delta); /* unlocks */ 943 return kr; 944} 945 946 947/* 948 * Routine: mach_port_peek [kernel call] 949 * Purpose: 950 * Peek at the message queue for the specified receive 951 * right and return info about a message in the queue. 952 * 953 * On input, seqnop points to a sequence number value 954 * to match the message being peeked. If zero is specified 955 * as the seqno, the first message in the queue will be 956 * peeked. 957 * 958 * Only the following trailer types are currently supported: 959 * MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) 960 * 961 * or'ed with one of these element types: 962 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_NULL) 963 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SEQNO) 964 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER) 965 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT) 966 * 967 * On input, the value pointed to by trailer_sizep must be 968 * large enough to hold the requested trailer size. 969 * 970 * The message sequence number, id, size, requested trailer info 971 * and requested trailer size are returned in their respective 972 * output parameters upon success. 973 * 974 * Conditions: 975 * Nothing locked. 976 * Returns: 977 * KERN_SUCCESS Matching message found, out parameters set. 978 * KERN_INVALID_TASK The space is null or dead. 979 * KERN_INVALID_NAME The name doesn't denote a right. 980 * KERN_INVALID_RIGHT Name doesn't denote receive rights. 981 * KERN_INVALID_VALUE The input parameter values are out of bounds. 982 * KERN_FAILURE The requested message was not found. 983 */ 984 985kern_return_t 986mach_port_peek( 987 ipc_space_t space, 988 mach_port_name_t name, 989 mach_msg_trailer_type_t trailer_type, 990 mach_port_seqno_t *seqnop, 991 mach_msg_size_t *msg_sizep, 992 mach_msg_id_t *msg_idp, 993 mach_msg_trailer_info_t trailer_infop, 994 mach_msg_type_number_t *trailer_sizep) 995{ 996 ipc_port_t port; 997 kern_return_t kr; 998 boolean_t found; 999 mach_msg_max_trailer_t max_trailer; 1000 1001 if (space == IS_NULL) 1002 return KERN_INVALID_TASK; 1003 1004 if (!MACH_PORT_VALID(name)) 1005 return KERN_INVALID_RIGHT; 1006 1007 /* 1008 * We don't allow anything greater than the audit trailer - to avoid 1009 * leaking the context pointer and to avoid variable-sized context issues. 1010 */ 1011 if (GET_RCV_ELEMENTS(trailer_type) > MACH_RCV_TRAILER_AUDIT || 1012 REQUESTED_TRAILER_SIZE(TRUE, trailer_type) > *trailer_sizep) 1013 return KERN_INVALID_VALUE; 1014 1015 *trailer_sizep = REQUESTED_TRAILER_SIZE(TRUE, trailer_type); 1016 1017 kr = ipc_port_translate_receive(space, name, &port); 1018 if (kr != KERN_SUCCESS) 1019 return kr; 1020 1021 /* Port locked and active */ 1022 1023 found = ipc_mqueue_peek(&port->ip_messages, seqnop, 1024 msg_sizep, msg_idp, &max_trailer); 1025 ip_unlock(port); 1026 1027 if (found != TRUE) 1028 return KERN_FAILURE; 1029 1030 max_trailer.msgh_seqno = *seqnop; 1031 memcpy(trailer_infop, &max_trailer, *trailer_sizep); 1032 1033 return KERN_SUCCESS; 1034} 1035 1036/* 1037 * Routine: mach_port_set_mscount [kernel call] 1038 * Purpose: 1039 * Changes a receive right's make-send count. 1040 * Conditions: 1041 * Nothing locked. 1042 * Returns: 1043 * KERN_SUCCESS Set make-send count. 1044 * KERN_INVALID_TASK The space is null. 1045 * KERN_INVALID_TASK The space is dead. 1046 * KERN_INVALID_NAME The name doesn't denote a right. 1047 * KERN_INVALID_RIGHT Name doesn't denote receive rights. 1048 */ 1049 1050kern_return_t 1051mach_port_set_mscount( 1052 ipc_space_t space, 1053 mach_port_name_t name, 1054 mach_port_mscount_t mscount) 1055{ 1056 ipc_port_t port; 1057 kern_return_t kr; 1058 1059 if (space == IS_NULL) 1060 return KERN_INVALID_TASK; 1061 1062 if (!MACH_PORT_VALID(name)) 1063 return KERN_INVALID_RIGHT; 1064 1065 kr = ipc_port_translate_receive(space, name, &port); 1066 if (kr != KERN_SUCCESS) 1067 return kr; 1068 /* port is locked and active */ 1069 1070 ipc_port_set_mscount(port, mscount); 1071 1072 ip_unlock(port); 1073 return KERN_SUCCESS; 1074} 1075 1076/* 1077 * Routine: mach_port_set_seqno [kernel call] 1078 * Purpose: 1079 * Changes a receive right's sequence number. 1080 * Conditions: 1081 * Nothing locked. 1082 * Returns: 1083 * KERN_SUCCESS Set sequence number. 1084 * KERN_INVALID_TASK The space is null. 1085 * KERN_INVALID_TASK The space is dead. 1086 * KERN_INVALID_NAME The name doesn't denote a right. 1087 * KERN_INVALID_RIGHT Name doesn't denote receive rights. 1088 */ 1089 1090kern_return_t 1091mach_port_set_seqno( 1092 ipc_space_t space, 1093 mach_port_name_t name, 1094 mach_port_seqno_t seqno) 1095{ 1096 ipc_port_t port; 1097 kern_return_t kr; 1098 1099 if (space == IS_NULL) 1100 return KERN_INVALID_TASK; 1101 1102 if (!MACH_PORT_VALID(name)) 1103 return KERN_INVALID_RIGHT; 1104 1105 kr = ipc_port_translate_receive(space, name, &port); 1106 if (kr != KERN_SUCCESS) 1107 return kr; 1108 /* port is locked and active */ 1109 1110 ipc_mqueue_set_seqno(&port->ip_messages, seqno); 1111 1112 ip_unlock(port); 1113 return KERN_SUCCESS; 1114} 1115 1116/* 1117 * Routine: mach_port_get_context [kernel call] 1118 * Purpose: 1119 * Returns a receive right's context pointer. 1120 * Conditions: 1121 * Nothing locked. 1122 * Returns: 1123 * KERN_SUCCESS Set context pointer. 1124 * KERN_INVALID_TASK The space is null. 1125 * KERN_INVALID_TASK The space is dead. 1126 * KERN_INVALID_NAME The name doesn't denote a right. 1127 * KERN_INVALID_RIGHT Name doesn't denote receive rights. 1128 */ 1129 1130kern_return_t 1131mach_port_get_context( 1132 ipc_space_t space, 1133 mach_port_name_t name, 1134 mach_vm_address_t *context) 1135{ 1136 ipc_port_t port; 1137 kern_return_t kr; 1138 1139 if (space == IS_NULL) 1140 return KERN_INVALID_TASK; 1141 1142 if (!MACH_PORT_VALID(name)) 1143 return KERN_INVALID_RIGHT; 1144 1145 kr = ipc_port_translate_receive(space, name, &port); 1146 if (kr != KERN_SUCCESS) 1147 return kr; 1148 1149 /* Port locked and active */ 1150 1151 /* For strictly guarded ports, return empty context (which acts as guard) */ 1152 if (port->ip_strict_guard) 1153 *context = 0; 1154 else 1155 *context = port->ip_context; 1156 1157 ip_unlock(port); 1158 return KERN_SUCCESS; 1159} 1160 1161 1162/* 1163 * Routine: mach_port_set_context [kernel call] 1164 * Purpose: 1165 * Changes a receive right's context pointer. 1166 * Conditions: 1167 * Nothing locked. 1168 * Returns: 1169 * KERN_SUCCESS Set context pointer. 1170 * KERN_INVALID_TASK The space is null. 1171 * KERN_INVALID_TASK The space is dead. 1172 * KERN_INVALID_NAME The name doesn't denote a right. 1173 * KERN_INVALID_RIGHT Name doesn't denote receive rights. 1174 */ 1175 1176kern_return_t 1177mach_port_set_context( 1178 ipc_space_t space, 1179 mach_port_name_t name, 1180 mach_vm_address_t context) 1181{ 1182 ipc_port_t port; 1183 kern_return_t kr; 1184 1185 if (space == IS_NULL) 1186 return KERN_INVALID_TASK; 1187 1188 if (!MACH_PORT_VALID(name)) 1189 return KERN_INVALID_RIGHT; 1190 1191 kr = ipc_port_translate_receive(space, name, &port); 1192 if (kr != KERN_SUCCESS) 1193 return kr; 1194 1195 /* port is locked and active */ 1196 if(port->ip_strict_guard) { 1197 uint64_t portguard = port->ip_context; 1198 ip_unlock(port); 1199 /* For strictly guarded ports, disallow overwriting context; Raise Exception */ 1200 mach_port_guard_exception(name, context, portguard, kGUARD_EXC_SET_CONTEXT); 1201 return KERN_INVALID_ARGUMENT; 1202 } 1203 1204 port->ip_context = context; 1205 1206 ip_unlock(port); 1207 return KERN_SUCCESS; 1208} 1209 1210 1211/* 1212 * Routine: mach_port_get_set_status [kernel call] 1213 * Purpose: 1214 * Retrieves a list of members in a port set. 1215 * Returns the space's name for each receive right member. 1216 * Conditions: 1217 * Nothing locked. 1218 * Returns: 1219 * KERN_SUCCESS Retrieved list of members. 1220 * KERN_INVALID_TASK The space is null. 1221 * KERN_INVALID_TASK The space is dead. 1222 * KERN_INVALID_NAME The name doesn't denote a right. 1223 * KERN_INVALID_RIGHT Name doesn't denote a port set. 1224 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. 1225 */ 1226 1227kern_return_t 1228mach_port_get_set_status( 1229 ipc_space_t space, 1230 mach_port_name_t name, 1231 mach_port_name_t **members, 1232 mach_msg_type_number_t *membersCnt) 1233{ 1234 ipc_entry_num_t actual; /* this many members */ 1235 ipc_entry_num_t maxnames; /* space for this many members */ 1236 kern_return_t kr; 1237 1238 vm_size_t size; /* size of allocated memory */ 1239 vm_offset_t addr; /* allocated memory */ 1240 vm_map_copy_t memory; /* copied-in memory */ 1241 1242 if (space == IS_NULL) 1243 return KERN_INVALID_TASK; 1244 1245 if (!MACH_PORT_VALID(name)) 1246 return KERN_INVALID_RIGHT; 1247 1248 size = VM_MAP_PAGE_SIZE(ipc_kernel_map); /* initial guess */ 1249 1250 for (;;) { 1251 mach_port_name_t *names; 1252 ipc_object_t psobj; 1253 ipc_pset_t pset; 1254 1255 kr = vm_allocate(ipc_kernel_map, &addr, size, VM_FLAGS_ANYWHERE); 1256 if (kr != KERN_SUCCESS) 1257 return KERN_RESOURCE_SHORTAGE; 1258 1259 /* can't fault while we hold locks */ 1260 1261 kr = vm_map_wire(ipc_kernel_map, addr, addr + size, 1262 VM_PROT_READ|VM_PROT_WRITE, FALSE); 1263 assert(kr == KERN_SUCCESS); 1264 1265 kr = ipc_object_translate(space, name, MACH_PORT_RIGHT_PORT_SET, &psobj); 1266 if (kr != KERN_SUCCESS) { 1267 kmem_free(ipc_kernel_map, addr, size); 1268 return kr; 1269 } 1270 1271 /* just use a portset reference from here on out */ 1272 pset = (ipc_pset_t) psobj; 1273 ips_reference(pset); 1274 ips_unlock(pset); 1275 1276 names = (mach_port_name_t *) addr; 1277 maxnames = (ipc_entry_num_t)(size / sizeof(mach_port_name_t)); 1278 1279 ipc_mqueue_set_gather_member_names(&pset->ips_messages, maxnames, names, &actual); 1280 1281 /* release the portset reference */ 1282 ips_release(pset); 1283 1284 if (actual <= maxnames) 1285 break; 1286 1287 /* didn't have enough memory; allocate more */ 1288 kmem_free(ipc_kernel_map, addr, size); 1289 size = vm_map_round_page( 1290 (actual * sizeof(mach_port_name_t)), 1291 VM_MAP_PAGE_MASK(ipc_kernel_map)) + 1292 VM_MAP_PAGE_SIZE(ipc_kernel_map); 1293 } 1294 1295 if (actual == 0) { 1296 memory = VM_MAP_COPY_NULL; 1297 1298 kmem_free(ipc_kernel_map, addr, size); 1299 } else { 1300 vm_size_t size_used; 1301 vm_size_t vm_size_used; 1302 1303 size_used = actual * sizeof(mach_port_name_t); 1304 vm_size_used = vm_map_round_page( 1305 size_used, 1306 VM_MAP_PAGE_MASK(ipc_kernel_map)); 1307 1308 /* 1309 * Make used memory pageable and get it into 1310 * copied-in form. Free any unused memory. 1311 */ 1312 1313 kr = vm_map_unwire( 1314 ipc_kernel_map, 1315 vm_map_trunc_page(addr, 1316 VM_MAP_PAGE_MASK(ipc_kernel_map)), 1317 vm_map_round_page(addr + vm_size_used, 1318 VM_MAP_PAGE_MASK(ipc_kernel_map)), 1319 FALSE); 1320 assert(kr == KERN_SUCCESS); 1321 1322 kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr, 1323 (vm_map_size_t)size_used, TRUE, &memory); 1324 assert(kr == KERN_SUCCESS); 1325 1326 if (vm_size_used != size) 1327 kmem_free(ipc_kernel_map, 1328 addr + vm_size_used, size - vm_size_used); 1329 } 1330 1331 *members = (mach_port_name_t *) memory; 1332 *membersCnt = actual; 1333 return KERN_SUCCESS; 1334} 1335 1336/* 1337 * Routine: mach_port_move_member [kernel call] 1338 * Purpose: 1339 * If after is MACH_PORT_NULL, removes member 1340 * from the port set it is in. Otherwise, adds 1341 * member to after, removing it from any set 1342 * it might already be in. 1343 * Conditions: 1344 * Nothing locked. 1345 * Returns: 1346 * KERN_SUCCESS Moved the port. 1347 * KERN_INVALID_TASK The space is null. 1348 * KERN_INVALID_TASK The space is dead. 1349 * KERN_INVALID_NAME Member didn't denote a right. 1350 * KERN_INVALID_RIGHT Member didn't denote a receive right. 1351 * KERN_INVALID_NAME After didn't denote a right. 1352 * KERN_INVALID_RIGHT After didn't denote a port set right. 1353 * KERN_NOT_IN_SET 1354 * After is MACH_PORT_NULL and Member isn't in a port set. 1355 */ 1356 1357kern_return_t 1358mach_port_move_member( 1359 ipc_space_t space, 1360 mach_port_name_t member, 1361 mach_port_name_t after) 1362{ 1363 ipc_entry_t entry; 1364 ipc_port_t port; 1365 ipc_pset_t nset; 1366 kern_return_t kr; 1367 wait_queue_link_t wql; 1368 queue_head_t links_data; 1369 queue_t links = &links_data; 1370 1371 if (space == IS_NULL) 1372 return KERN_INVALID_TASK; 1373 1374 if (!MACH_PORT_VALID(member)) 1375 return KERN_INVALID_RIGHT; 1376 1377 if (after == MACH_PORT_DEAD) 1378 return KERN_INVALID_RIGHT; 1379 else if (after == MACH_PORT_NULL) 1380 wql = WAIT_QUEUE_LINK_NULL; 1381 else 1382 wql = wait_queue_link_allocate(); 1383 1384 queue_init(links); 1385 1386 kr = ipc_right_lookup_read(space, member, &entry); 1387 if (kr != KERN_SUCCESS) 1388 goto done; 1389 /* space is read-locked and active */ 1390 1391 if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0) { 1392 is_read_unlock(space); 1393 kr = KERN_INVALID_RIGHT; 1394 goto done; 1395 } 1396 1397 port = (ipc_port_t) entry->ie_object; 1398 assert(port != IP_NULL); 1399 1400 if (after == MACH_PORT_NULL) 1401 nset = IPS_NULL; 1402 else { 1403 entry = ipc_entry_lookup(space, after); 1404 if (entry == IE_NULL) { 1405 is_read_unlock(space); 1406 kr = KERN_INVALID_NAME; 1407 goto done; 1408 } 1409 1410 if ((entry->ie_bits & MACH_PORT_TYPE_PORT_SET) == 0) { 1411 is_read_unlock(space); 1412 kr = KERN_INVALID_RIGHT; 1413 goto done; 1414 } 1415 1416 nset = (ipc_pset_t) entry->ie_object; 1417 assert(nset != IPS_NULL); 1418 } 1419 ip_lock(port); 1420 ipc_pset_remove_from_all(port, links); 1421 1422 if (nset != IPS_NULL) { 1423 ips_lock(nset); 1424 kr = ipc_pset_add(nset, port, wql); 1425 ips_unlock(nset); 1426 } 1427 ip_unlock(port); 1428 is_read_unlock(space); 1429 1430 done: 1431 if (kr != KERN_SUCCESS && wql != WAIT_QUEUE_LINK_NULL) 1432 wait_queue_link_free(wql); 1433 while(!queue_empty(links)) { 1434 wql = (wait_queue_link_t) dequeue(links); 1435 wait_queue_link_free(wql); 1436 } 1437 1438 return kr; 1439} 1440 1441/* 1442 * Routine: mach_port_request_notification [kernel call] 1443 * Purpose: 1444 * Requests a notification. The caller supplies 1445 * a send-once right for the notification to use, 1446 * and the call returns the previously registered 1447 * send-once right, if any. Possible types: 1448 * 1449 * MACH_NOTIFY_PORT_DESTROYED 1450 * Requests a port-destroyed notification 1451 * for a receive right. Sync should be zero. 1452 * MACH_NOTIFY_NO_SENDERS 1453 * Requests a no-senders notification for a 1454 * receive right. If there are currently no 1455 * senders, sync is less than or equal to the 1456 * current make-send count, and a send-once right 1457 * is supplied, then an immediate no-senders 1458 * notification is generated. 1459 * MACH_NOTIFY_DEAD_NAME 1460 * Requests a dead-name notification for a send 1461 * or receive right. If the name is already a 1462 * dead name, sync is non-zero, and a send-once 1463 * right is supplied, then an immediate dead-name 1464 * notification is generated. 1465 * Conditions: 1466 * Nothing locked. 1467 * Returns: 1468 * KERN_SUCCESS Requested a notification. 1469 * KERN_INVALID_TASK The space is null. 1470 * KERN_INVALID_TASK The space is dead. 1471 * KERN_INVALID_VALUE Bad id value. 1472 * KERN_INVALID_NAME Name doesn't denote a right. 1473 * KERN_INVALID_RIGHT Name doesn't denote appropriate right. 1474 * KERN_INVALID_CAPABILITY The notify port is dead. 1475 * MACH_NOTIFY_PORT_DESTROYED: 1476 * KERN_INVALID_VALUE Sync isn't zero. 1477 * MACH_NOTIFY_DEAD_NAME: 1478 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. 1479 * KERN_INVALID_ARGUMENT Name denotes dead name, but 1480 * sync is zero or notify is IP_NULL. 1481 * KERN_UREFS_OVERFLOW Name denotes dead name, but 1482 * generating immediate notif. would overflow urefs. 1483 */ 1484 1485kern_return_t 1486mach_port_request_notification( 1487 ipc_space_t space, 1488 mach_port_name_t name, 1489 mach_msg_id_t id, 1490 mach_port_mscount_t sync, 1491 ipc_port_t notify, 1492 ipc_port_t *previousp) 1493{ 1494 kern_return_t kr; 1495 1496 if (space == IS_NULL) 1497 return KERN_INVALID_TASK; 1498 1499 if (notify == IP_DEAD) 1500 return KERN_INVALID_CAPABILITY; 1501 1502#if NOTYET 1503 /* 1504 * Requesting notifications on RPC ports is an error. 1505 */ 1506 { 1507 ipc_port_t port; 1508 ipc_entry_t entry; 1509 1510 kr = ipc_right_lookup_write(space, name, &entry); 1511 if (kr != KERN_SUCCESS) 1512 return kr; 1513 1514 port = (ipc_port_t) entry->ie_object; 1515 1516 if (port->ip_subsystem != NULL) { 1517 is_write_unlock(space); 1518 panic("mach_port_request_notification: on RPC port!!"); 1519 return KERN_INVALID_CAPABILITY; 1520 } 1521 is_write_unlock(space); 1522 } 1523#endif /* NOTYET */ 1524 1525 1526 switch (id) { 1527 case MACH_NOTIFY_PORT_DESTROYED: { 1528 ipc_port_t port, previous; 1529 1530 if (sync != 0) 1531 return KERN_INVALID_VALUE; 1532 1533 if (!MACH_PORT_VALID(name)) 1534 return KERN_INVALID_RIGHT; 1535 1536 kr = ipc_port_translate_receive(space, name, &port); 1537 if (kr != KERN_SUCCESS) 1538 return kr; 1539 /* port is locked and active */ 1540 1541 ipc_port_pdrequest(port, notify, &previous); 1542 /* port is unlocked */ 1543 1544 *previousp = previous; 1545 break; 1546 } 1547 1548 case MACH_NOTIFY_NO_SENDERS: { 1549 ipc_port_t port; 1550 1551 if (!MACH_PORT_VALID(name)) 1552 return KERN_INVALID_RIGHT; 1553 1554 kr = ipc_port_translate_receive(space, name, &port); 1555 if (kr != KERN_SUCCESS) 1556 return kr; 1557 /* port is locked and active */ 1558 1559 ipc_port_nsrequest(port, sync, notify, previousp); 1560 /* port is unlocked */ 1561 break; 1562 } 1563 1564 case MACH_NOTIFY_SEND_POSSIBLE: 1565 1566 if (!MACH_PORT_VALID(name)) { 1567 return KERN_INVALID_ARGUMENT; 1568 } 1569 1570 kr = ipc_right_request_alloc(space, name, sync != 0, 1571 TRUE, notify, previousp); 1572 if (kr != KERN_SUCCESS) 1573 return kr; 1574 break; 1575 1576 case MACH_NOTIFY_DEAD_NAME: 1577 1578 if (!MACH_PORT_VALID(name)) { 1579 /* 1580 * Already dead. 1581 * Should do immediate delivery check - 1582 * will do that in the near future. 1583 */ 1584 return KERN_INVALID_ARGUMENT; 1585 } 1586 1587 kr = ipc_right_request_alloc(space, name, sync != 0, 1588 FALSE, notify, previousp); 1589 if (kr != KERN_SUCCESS) 1590 return kr; 1591 break; 1592 1593 default: 1594 return KERN_INVALID_VALUE; 1595 } 1596 1597 return KERN_SUCCESS; 1598} 1599 1600/* 1601 * Routine: mach_port_insert_right [kernel call] 1602 * Purpose: 1603 * Inserts a right into a space, as if the space 1604 * voluntarily received the right in a message, 1605 * except that the right gets the specified name. 1606 * Conditions: 1607 * Nothing locked. 1608 * Returns: 1609 * KERN_SUCCESS Inserted the right. 1610 * KERN_INVALID_TASK The space is null. 1611 * KERN_INVALID_TASK The space is dead. 1612 * KERN_INVALID_VALUE The name isn't a legal name. 1613 * KERN_NAME_EXISTS The name already denotes a right. 1614 * KERN_INVALID_VALUE Message doesn't carry a port right. 1615 * KERN_INVALID_CAPABILITY Port is null or dead. 1616 * KERN_UREFS_OVERFLOW Urefs limit would be exceeded. 1617 * KERN_RIGHT_EXISTS Space has rights under another name. 1618 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. 1619 */ 1620 1621kern_return_t 1622mach_port_insert_right( 1623 ipc_space_t space, 1624 mach_port_name_t name, 1625 ipc_port_t poly, 1626 mach_msg_type_name_t polyPoly) 1627{ 1628 if (space == IS_NULL) 1629 return KERN_INVALID_TASK; 1630 1631 if (!MACH_PORT_VALID(name) || 1632 !MACH_MSG_TYPE_PORT_ANY_RIGHT(polyPoly)) 1633 return KERN_INVALID_VALUE; 1634 1635 if (!IO_VALID((ipc_object_t) poly)) 1636 return KERN_INVALID_CAPABILITY; 1637 1638 return ipc_object_copyout_name(space, (ipc_object_t) poly, 1639 polyPoly, FALSE, name); 1640} 1641 1642/* 1643 * Routine: mach_port_extract_right [kernel call] 1644 * Purpose: 1645 * Extracts a right from a space, as if the space 1646 * voluntarily sent the right to the caller. 1647 * Conditions: 1648 * Nothing locked. 1649 * Returns: 1650 * KERN_SUCCESS Extracted the right. 1651 * KERN_INVALID_TASK The space is null. 1652 * KERN_INVALID_TASK The space is dead. 1653 * KERN_INVALID_VALUE Requested type isn't a port right. 1654 * KERN_INVALID_NAME Name doesn't denote a right. 1655 * KERN_INVALID_RIGHT Name doesn't denote appropriate right. 1656 */ 1657 1658kern_return_t 1659mach_port_extract_right( 1660 ipc_space_t space, 1661 mach_port_name_t name, 1662 mach_msg_type_name_t msgt_name, 1663 ipc_port_t *poly, 1664 mach_msg_type_name_t *polyPoly) 1665{ 1666 kern_return_t kr; 1667 1668 if (space == IS_NULL) 1669 return KERN_INVALID_TASK; 1670 1671 if (!MACH_MSG_TYPE_PORT_ANY(msgt_name)) 1672 return KERN_INVALID_VALUE; 1673 1674 if (!MACH_PORT_VALID(name)) { 1675 /* 1676 * really should copy out a dead name, if it is a send or 1677 * send-once right being copied, but instead return an 1678 * error for now. 1679 */ 1680 return KERN_INVALID_RIGHT; 1681 } 1682 1683 kr = ipc_object_copyin(space, name, msgt_name, (ipc_object_t *) poly); 1684 1685 if (kr == KERN_SUCCESS) 1686 *polyPoly = ipc_object_copyin_type(msgt_name); 1687 return kr; 1688} 1689 1690/* 1691 * Routine: mach_port_get_status_helper [helper] 1692 * Purpose: 1693 * Populates a mach_port_status_t structure with 1694 * port information. 1695 * Conditions: 1696 * Port needs to be locked 1697 * Returns: 1698 * None. 1699 */ 1700void mach_port_get_status_helper( 1701 ipc_port_t port, 1702 mach_port_status_t *statusp) 1703{ 1704 spl_t s; 1705 statusp->mps_pset = port->ip_pset_count; 1706 1707 s = splsched(); 1708 imq_lock(&port->ip_messages); 1709 statusp->mps_seqno = port->ip_messages.imq_seqno; 1710 statusp->mps_qlimit = port->ip_messages.imq_qlimit; 1711 statusp->mps_msgcount = port->ip_messages.imq_msgcount; 1712 imq_unlock(&port->ip_messages); 1713 splx(s); 1714 1715 statusp->mps_mscount = port->ip_mscount; 1716 statusp->mps_sorights = port->ip_sorights; 1717 statusp->mps_srights = port->ip_srights > 0; 1718 statusp->mps_pdrequest = port->ip_pdrequest != IP_NULL; 1719 statusp->mps_nsrequest = port->ip_nsrequest != IP_NULL; 1720 statusp->mps_flags = 0; 1721 if (port->ip_impdonation) { 1722 statusp->mps_flags |= MACH_PORT_STATUS_FLAG_IMP_DONATION; 1723 if (port->ip_tempowner) { 1724 statusp->mps_flags |= MACH_PORT_STATUS_FLAG_TEMPOWNER; 1725 if (IIT_NULL != port->ip_imp_task) { 1726 statusp->mps_flags |= MACH_PORT_STATUS_FLAG_TASKPTR; 1727 } 1728 } 1729 } 1730 if (port->ip_guarded) { 1731 statusp->mps_flags |= MACH_PORT_STATUS_FLAG_GUARDED; 1732 if (port->ip_strict_guard) { 1733 statusp->mps_flags |= MACH_PORT_STATUS_FLAG_STRICT_GUARD; 1734 } 1735 } 1736 return; 1737} 1738 1739 1740 1741kern_return_t 1742mach_port_get_attributes( 1743 ipc_space_t space, 1744 mach_port_name_t name, 1745 int flavor, 1746 mach_port_info_t info, 1747 mach_msg_type_number_t *count) 1748{ 1749 ipc_port_t port; 1750 kern_return_t kr; 1751 1752 if (space == IS_NULL) 1753 return KERN_INVALID_TASK; 1754 1755 switch (flavor) { 1756 case MACH_PORT_LIMITS_INFO: { 1757 mach_port_limits_t *lp = (mach_port_limits_t *)info; 1758 1759 if (*count < MACH_PORT_LIMITS_INFO_COUNT) 1760 return KERN_FAILURE; 1761 1762 if (!MACH_PORT_VALID(name)) { 1763 *count = 0; 1764 break; 1765 } 1766 1767 kr = ipc_port_translate_receive(space, name, &port); 1768 if (kr != KERN_SUCCESS) 1769 return kr; 1770 /* port is locked and active */ 1771 1772 lp->mpl_qlimit = port->ip_messages.imq_qlimit; 1773 *count = MACH_PORT_LIMITS_INFO_COUNT; 1774 ip_unlock(port); 1775 break; 1776 } 1777 1778 case MACH_PORT_RECEIVE_STATUS: { 1779 mach_port_status_t *statusp = (mach_port_status_t *)info; 1780 1781 if (*count < MACH_PORT_RECEIVE_STATUS_COUNT) 1782 return KERN_FAILURE; 1783 1784 if (!MACH_PORT_VALID(name)) 1785 return KERN_INVALID_RIGHT; 1786 1787 kr = ipc_port_translate_receive(space, name, &port); 1788 if (kr != KERN_SUCCESS) 1789 return kr; 1790 /* port is locked and active */ 1791 mach_port_get_status_helper(port, statusp); 1792 *count = MACH_PORT_RECEIVE_STATUS_COUNT; 1793 ip_unlock(port); 1794 break; 1795 } 1796 1797 case MACH_PORT_DNREQUESTS_SIZE: { 1798 ipc_port_request_t table; 1799 1800 if (*count < MACH_PORT_DNREQUESTS_SIZE_COUNT) 1801 return KERN_FAILURE; 1802 1803 if (!MACH_PORT_VALID(name)) { 1804 *(int *)info = 0; 1805 break; 1806 } 1807 1808 kr = ipc_port_translate_receive(space, name, &port); 1809 if (kr != KERN_SUCCESS) 1810 return kr; 1811 /* port is locked and active */ 1812 1813 table = port->ip_requests; 1814 if (table == IPR_NULL) 1815 *(int *)info = 0; 1816 else 1817 *(int *)info = table->ipr_size->its_size; 1818 *count = MACH_PORT_DNREQUESTS_SIZE_COUNT; 1819 ip_unlock(port); 1820 break; 1821 } 1822 1823 case MACH_PORT_INFO_EXT: { 1824 mach_port_info_ext_t *mp_info = (mach_port_info_ext_t *)info; 1825 if (*count < MACH_PORT_INFO_EXT_COUNT) 1826 return KERN_FAILURE; 1827 1828 if (!MACH_PORT_VALID(name)) 1829 return KERN_INVALID_RIGHT; 1830 1831 kr = ipc_port_translate_receive(space, name, &port); 1832 if (kr != KERN_SUCCESS) 1833 return kr; 1834 /* port is locked and active */ 1835 mach_port_get_status_helper(port, &mp_info->mpie_status); 1836 mp_info->mpie_boost_cnt = port->ip_impcount; 1837 *count = MACH_PORT_INFO_EXT_COUNT; 1838 ip_unlock(port); 1839 break; 1840 } 1841 1842 default: 1843 return KERN_INVALID_ARGUMENT; 1844 /*NOTREACHED*/ 1845 } 1846 1847 return KERN_SUCCESS; 1848} 1849 1850kern_return_t 1851mach_port_set_attributes( 1852 ipc_space_t space, 1853 mach_port_name_t name, 1854 int flavor, 1855 mach_port_info_t info, 1856 mach_msg_type_number_t count) 1857{ 1858 ipc_port_t port; 1859 kern_return_t kr; 1860 1861 if (space == IS_NULL) 1862 return KERN_INVALID_TASK; 1863 1864 switch (flavor) { 1865 1866 case MACH_PORT_LIMITS_INFO: { 1867 mach_port_limits_t *mplp = (mach_port_limits_t *)info; 1868 1869 if (count < MACH_PORT_LIMITS_INFO_COUNT) 1870 return KERN_FAILURE; 1871 1872 if (mplp->mpl_qlimit > MACH_PORT_QLIMIT_MAX) 1873 return KERN_INVALID_VALUE; 1874 1875 if (!MACH_PORT_VALID(name)) 1876 return KERN_INVALID_RIGHT; 1877 1878 kr = ipc_port_translate_receive(space, name, &port); 1879 if (kr != KERN_SUCCESS) 1880 return kr; 1881 /* port is locked and active */ 1882 1883 ipc_mqueue_set_qlimit(&port->ip_messages, mplp->mpl_qlimit); 1884 ip_unlock(port); 1885 break; 1886 } 1887 case MACH_PORT_DNREQUESTS_SIZE: { 1888 if (count < MACH_PORT_DNREQUESTS_SIZE_COUNT) 1889 return KERN_FAILURE; 1890 1891 if (!MACH_PORT_VALID(name)) 1892 return KERN_INVALID_RIGHT; 1893 1894 kr = ipc_port_translate_receive(space, name, &port); 1895 if (kr != KERN_SUCCESS) 1896 return kr; 1897 /* port is locked and active */ 1898 1899 kr = ipc_port_request_grow(port, *(int *)info); 1900 if (kr != KERN_SUCCESS) 1901 return kr; 1902 break; 1903 } 1904 case MACH_PORT_TEMPOWNER: 1905 if (!MACH_PORT_VALID(name)) 1906 return KERN_INVALID_RIGHT; 1907 1908 ipc_importance_task_t release_imp_task = IIT_NULL; 1909 natural_t assertcnt = 0; 1910 1911 kr = ipc_port_translate_receive(space, name, &port); 1912 if (kr != KERN_SUCCESS) 1913 return kr; 1914 /* port is locked and active */ 1915 1916 /* 1917 * don't allow temp-owner importance donation if user 1918 * associated it with a kobject already (timer, host_notify target). 1919 */ 1920 if (is_ipc_kobject(ip_kotype(port))) { 1921 ip_unlock(port); 1922 return KERN_INVALID_ARGUMENT; 1923 } 1924 1925 if (port->ip_tempowner != 0) { 1926 if (IIT_NULL != port->ip_imp_task) { 1927 release_imp_task = port->ip_imp_task; 1928 port->ip_imp_task = IIT_NULL; 1929 assertcnt = port->ip_impcount; 1930 } 1931 } else { 1932 assertcnt = port->ip_impcount; 1933 } 1934 1935 port->ip_impdonation = 1; 1936 port->ip_tempowner = 1; 1937 ip_unlock(port); 1938 1939#if IMPORTANCE_INHERITANCE 1940 /* drop assertions from previous destination task */ 1941 if (release_imp_task != IIT_NULL) { 1942 assert(ipc_importance_task_is_any_receiver_type(release_imp_task)); 1943 if (assertcnt > 0) 1944 ipc_importance_task_drop_internal_assertion(release_imp_task, assertcnt); 1945 ipc_importance_task_release(release_imp_task); 1946 } else if (assertcnt > 0) { 1947 release_imp_task = current_task()->task_imp_base; 1948 if (release_imp_task != IIT_NULL && 1949 ipc_importance_task_is_any_receiver_type(release_imp_task)) { 1950 ipc_importance_task_drop_internal_assertion(release_imp_task, assertcnt); 1951 } 1952 } 1953#else 1954 if (release_imp_task != IIT_NULL) 1955 ipc_importance_task_release(release_imp_task); 1956#endif /* IMPORTANCE_INHERITANCE */ 1957 1958 break; 1959 1960#if IMPORTANCE_INHERITANCE 1961 case MACH_PORT_DENAP_RECEIVER: 1962 case MACH_PORT_IMPORTANCE_RECEIVER: 1963 if (!MACH_PORT_VALID(name)) 1964 return KERN_INVALID_RIGHT; 1965 1966 kr = ipc_port_translate_receive(space, name, &port); 1967 if (kr != KERN_SUCCESS) 1968 return kr; 1969 1970 /* 1971 * don't allow importance donation if user associated 1972 * it with a kobject already (timer, host_notify target). 1973 */ 1974 if (is_ipc_kobject(ip_kotype(port))) { 1975 ip_unlock(port); 1976 return KERN_INVALID_ARGUMENT; 1977 } 1978 1979 /* port is locked and active */ 1980 port->ip_impdonation = 1; 1981 ip_unlock(port); 1982 1983 break; 1984#endif /* IMPORTANCE_INHERITANCE */ 1985 1986 default: 1987 return KERN_INVALID_ARGUMENT; 1988 /*NOTREACHED*/ 1989 } 1990 return KERN_SUCCESS; 1991} 1992 1993/* 1994 * Routine: mach_port_insert_member [kernel call] 1995 * Purpose: 1996 * Add the receive right, specified by name, to 1997 * a portset. 1998 * The port cannot already be a member of the set. 1999 * Conditions: 2000 * Nothing locked. 2001 * Returns: 2002 * KERN_SUCCESS Moved the port. 2003 * KERN_INVALID_TASK The space is null. 2004 * KERN_INVALID_TASK The space is dead. 2005 * KERN_INVALID_NAME name didn't denote a right. 2006 * KERN_INVALID_RIGHT name didn't denote a receive right. 2007 * KERN_INVALID_NAME pset_name didn't denote a right. 2008 * KERN_INVALID_RIGHT pset_name didn't denote a portset right. 2009 * KERN_ALREADY_IN_SET name was already a member of pset. 2010 */ 2011 2012kern_return_t 2013mach_port_insert_member( 2014 ipc_space_t space, 2015 mach_port_name_t name, 2016 mach_port_name_t psname) 2017{ 2018 ipc_object_t obj; 2019 ipc_object_t psobj; 2020 kern_return_t kr; 2021 wait_queue_link_t wql; 2022 2023 if (space == IS_NULL) 2024 return KERN_INVALID_TASK; 2025 2026 if (!MACH_PORT_VALID(name) || !MACH_PORT_VALID(psname)) 2027 return KERN_INVALID_RIGHT; 2028 2029 wql = wait_queue_link_allocate(); 2030 2031 kr = ipc_object_translate_two(space, 2032 name, MACH_PORT_RIGHT_RECEIVE, &obj, 2033 psname, MACH_PORT_RIGHT_PORT_SET, &psobj); 2034 if (kr != KERN_SUCCESS) 2035 goto done; 2036 2037 /* obj and psobj are locked (and were locked in that order) */ 2038 assert(psobj != IO_NULL); 2039 assert(obj != IO_NULL); 2040 2041 kr = ipc_pset_add((ipc_pset_t)psobj, (ipc_port_t)obj, wql); 2042 io_unlock(psobj); 2043 io_unlock(obj); 2044 2045 done: 2046 if (kr != KERN_SUCCESS) 2047 wait_queue_link_free(wql); 2048 2049 return kr; 2050} 2051 2052/* 2053 * Routine: mach_port_extract_member [kernel call] 2054 * Purpose: 2055 * Remove a port from one portset that it is a member of. 2056 * Conditions: 2057 * Nothing locked. 2058 * Returns: 2059 * KERN_SUCCESS Moved the port. 2060 * KERN_INVALID_TASK The space is null. 2061 * KERN_INVALID_TASK The space is dead. 2062 * KERN_INVALID_NAME Member didn't denote a right. 2063 * KERN_INVALID_RIGHT Member didn't denote a receive right. 2064 * KERN_INVALID_NAME After didn't denote a right. 2065 * KERN_INVALID_RIGHT After didn't denote a port set right. 2066 * KERN_NOT_IN_SET 2067 * After is MACH_PORT_NULL and Member isn't in a port set. 2068 */ 2069 2070kern_return_t 2071mach_port_extract_member( 2072 ipc_space_t space, 2073 mach_port_name_t name, 2074 mach_port_name_t psname) 2075{ 2076 ipc_object_t psobj; 2077 ipc_object_t obj; 2078 kern_return_t kr; 2079 wait_queue_link_t wql = WAIT_QUEUE_LINK_NULL; 2080 2081 if (space == IS_NULL) 2082 return KERN_INVALID_TASK; 2083 2084 if (!MACH_PORT_VALID(name) || !MACH_PORT_VALID(psname)) 2085 return KERN_INVALID_RIGHT; 2086 2087 kr = ipc_object_translate_two(space, 2088 name, MACH_PORT_RIGHT_RECEIVE, &obj, 2089 psname, MACH_PORT_RIGHT_PORT_SET, &psobj); 2090 if (kr != KERN_SUCCESS) 2091 return kr; 2092 2093 /* obj and psobj are both locked (and were locked in that order) */ 2094 assert(psobj != IO_NULL); 2095 assert(obj != IO_NULL); 2096 2097 kr = ipc_pset_remove((ipc_pset_t)psobj, (ipc_port_t)obj, &wql); 2098 io_unlock(psobj); 2099 io_unlock(obj); 2100 2101 if (wql != WAIT_QUEUE_LINK_NULL) 2102 wait_queue_link_free(wql); 2103 2104 return kr; 2105} 2106 2107/* 2108 * task_set_port_space: 2109 * 2110 * Set port name space of task to specified size. 2111 */ 2112kern_return_t 2113task_set_port_space( 2114 ipc_space_t space, 2115 int table_entries) 2116{ 2117 kern_return_t kr; 2118 2119 is_write_lock(space); 2120 2121 if (!is_active(space)) { 2122 is_write_unlock(space); 2123 return KERN_INVALID_TASK; 2124 } 2125 2126 kr = ipc_entry_grow_table(space, table_entries); 2127 if (kr == KERN_SUCCESS) 2128 is_write_unlock(space); 2129 return kr; 2130} 2131 2132/* 2133 * Routine: mach_port_guard_locked [helper routine] 2134 * Purpose: 2135 * Sets a new guard for a locked port. 2136 * Conditions: 2137 * Port Locked. 2138 * Returns: 2139 * KERN_SUCCESS Port Guarded. 2140 * KERN_INVALID_ARGUMENT Port already contains a context/guard. 2141 */ 2142static kern_return_t 2143mach_port_guard_locked( 2144 ipc_port_t port, 2145 uint64_t guard, 2146 boolean_t strict) 2147{ 2148 if (port->ip_context) 2149 return KERN_INVALID_ARGUMENT; 2150 2151 port->ip_context = guard; 2152 port->ip_guarded = 1; 2153 port->ip_strict_guard = (strict)?1:0; 2154 return KERN_SUCCESS; 2155} 2156 2157/* 2158 * Routine: mach_port_unguard_locked [helper routine] 2159 * Purpose: 2160 * Removes guard for a locked port. 2161 * Conditions: 2162 * Port Locked. 2163 * Returns: 2164 * KERN_SUCCESS Port Unguarded. 2165 * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch. 2166 * This also raises a EXC_GUARD exception. 2167 */ 2168static kern_return_t 2169mach_port_unguard_locked( 2170 ipc_port_t port, 2171 mach_port_name_t name, 2172 uint64_t guard) 2173{ 2174 /* Port locked and active */ 2175 if (!port->ip_guarded) { 2176 /* Port already unguarded; Raise exception */ 2177 mach_port_guard_exception(name, guard, 0, kGUARD_EXC_UNGUARDED); 2178 return KERN_INVALID_ARGUMENT; 2179 } 2180 2181 if (port->ip_context != guard) { 2182 /* Incorrect guard; Raise exception */ 2183 mach_port_guard_exception(name, guard, port->ip_context, kGUARD_EXC_INCORRECT_GUARD); 2184 return KERN_INVALID_ARGUMENT; 2185 } 2186 2187 port->ip_context = 0; 2188 port->ip_guarded = port->ip_strict_guard = 0; 2189 return KERN_SUCCESS; 2190} 2191 2192 2193/* 2194 * Routine: mach_port_guard_exception [helper routine] 2195 * Purpose: 2196 * Marks the thread with AST_GUARD for mach port guard violation. 2197 * Also saves exception info in thread structure. 2198 * Conditions: 2199 * None. 2200 * Returns: 2201 * KERN_FAILURE Thread marked with AST_GUARD. 2202 */ 2203kern_return_t 2204mach_port_guard_exception( 2205 mach_port_name_t name, 2206 uint64_t inguard, 2207 uint64_t portguard, 2208 unsigned reason) 2209{ 2210 thread_t t = current_thread(); 2211 uint64_t code, subcode; 2212 2213 /* Log exception info to syslog */ 2214 printf( "Mach Port Guard Exception - " 2215 "Thread: 0x%x, " 2216 "Port Name: 0x%x, " 2217 "Expected Guard: 0x%x, " 2218 "Received Guard: 0x%x\n", 2219 (unsigned)t, 2220 (unsigned)name, 2221 (unsigned)portguard, 2222 (unsigned)inguard); 2223 2224 /* 2225 * EXC_GUARD namespace for mach ports 2226 * 2227 * 2228 * Mach Port guards use the exception codes like 2229 * 2230 * code: 2231 * +----------------------------------------------------------------+ 2232 * |[63:61] GUARD_TYPE_MACH_PORT | [60:32] flavor | [31:0] port name| 2233 * +----------------------------------------------------------------+ 2234 * 2235 * subcode: 2236 * +----------------------------------------------------------------+ 2237 * | [63:0] guard value | 2238 * +----------------------------------------------------------------+ 2239 */ 2240 2241 code = (((uint64_t)GUARD_TYPE_MACH_PORT) << 61) | 2242 (((uint64_t)reason) << 32) | 2243 ((uint64_t)name); 2244 subcode = (uint64_t)(portguard); 2245 2246 t->guard_exc_info.code = code; 2247 t->guard_exc_info.subcode = subcode; 2248 2249 /* Mark thread with AST_GUARD */ 2250 thread_guard_violation(t, GUARD_TYPE_MACH_PORT); 2251 return KERN_FAILURE; 2252} 2253 2254 2255/* 2256 * Routine: mach_port_guard_ast 2257 * Purpose: 2258 * Raises an exception for mach port guard violation. 2259 * Conditions: 2260 * None. 2261 * Returns: 2262 * None. 2263 */ 2264 2265void 2266mach_port_guard_ast(thread_t t) 2267{ 2268 mach_exception_data_type_t code[EXCEPTION_CODE_MAX]; 2269 2270 code[0] = t->guard_exc_info.code; 2271 code[1] = t->guard_exc_info.subcode; 2272 2273 /* Raise an EXC_GUARD exception */ 2274 exception_triage(EXC_GUARD, code, EXCEPTION_CODE_MAX); 2275 2276 /* Terminate task which caused the exception */ 2277 (void) task_terminate_internal(current_task()); 2278 return; 2279} 2280 2281/* 2282 * Routine: mach_port_construct [kernel call] 2283 * Purpose: 2284 * Constructs a mach port with the provided set of options. 2285 * Conditions: 2286 * None. 2287 * Returns: 2288 * KERN_SUCCESS The right is allocated. 2289 * KERN_INVALID_TASK The space is null. 2290 * KERN_INVALID_TASK The space is dead. 2291 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. 2292 * KERN_NO_SPACE No room in space for another right. 2293 * KERN_FAILURE Illegal option values requested. 2294 */ 2295 2296kern_return_t 2297mach_port_construct( 2298 ipc_space_t space, 2299 mach_port_options_t *options, 2300 uint64_t context, 2301 mach_port_name_t *name) 2302{ 2303 kern_return_t kr; 2304 ipc_port_t port; 2305 2306 if (space == IS_NULL) 2307 return (KERN_INVALID_TASK); 2308 2309 /* Allocate a new port in the IPC space */ 2310 kr = ipc_port_alloc(space, name, &port); 2311 if (kr != KERN_SUCCESS) 2312 return kr; 2313 2314 /* Port locked and active */ 2315 if (options->flags & MPO_CONTEXT_AS_GUARD) { 2316 kr = mach_port_guard_locked(port, (uint64_t) context, (options->flags & MPO_STRICT)); 2317 /* A newly allocated and locked port should always be guarded successfully */ 2318 assert(kr == KERN_SUCCESS); 2319 } else { 2320 port->ip_context = context; 2321 } 2322 2323 /* Unlock port */ 2324 ip_unlock(port); 2325 2326 /* Set port attributes as requested */ 2327 2328 if (options->flags & MPO_QLIMIT) { 2329 kr = mach_port_set_attributes(space, *name, MACH_PORT_LIMITS_INFO, 2330 (mach_port_info_t)&options->mpl, sizeof(options->mpl)/sizeof(int)); 2331 if (kr != KERN_SUCCESS) 2332 goto cleanup; 2333 } 2334 2335 if (options->flags & MPO_TEMPOWNER) { 2336 kr = mach_port_set_attributes(space, *name, MACH_PORT_TEMPOWNER, NULL, 0); 2337 if (kr != KERN_SUCCESS) 2338 goto cleanup; 2339 } 2340 2341 if (options->flags & MPO_IMPORTANCE_RECEIVER) { 2342 kr = mach_port_set_attributes(space, *name, MACH_PORT_IMPORTANCE_RECEIVER, NULL, 0); 2343 if (kr != KERN_SUCCESS) 2344 goto cleanup; 2345 } 2346 2347 if (options->flags & MPO_DENAP_RECEIVER) { 2348 kr = mach_port_set_attributes(space, *name, MACH_PORT_DENAP_RECEIVER, NULL, 0); 2349 if (kr != KERN_SUCCESS) 2350 goto cleanup; 2351 } 2352 2353 if (options->flags & MPO_INSERT_SEND_RIGHT) { 2354 kr = ipc_object_copyin(space, *name, MACH_MSG_TYPE_MAKE_SEND, (ipc_object_t *)&port); 2355 if (kr != KERN_SUCCESS) 2356 goto cleanup; 2357 2358 kr = mach_port_insert_right(space, *name, port, MACH_MSG_TYPE_PORT_SEND); 2359 if (kr != KERN_SUCCESS) 2360 goto cleanup; 2361 } 2362 2363 return KERN_SUCCESS; 2364 2365cleanup: 2366 /* Attempt to destroy port. If its already destroyed by some other thread, we're done */ 2367 (void) mach_port_destruct(space, *name, 0, context); 2368 return kr; 2369} 2370 2371/* 2372 * Routine: mach_port_destruct [kernel call] 2373 * Purpose: 2374 * Destroys a mach port with appropriate guard 2375 * Conditions: 2376 * None. 2377 * Returns: 2378 * KERN_SUCCESS The name is destroyed. 2379 * KERN_INVALID_TASK The space is null. 2380 * KERN_INVALID_TASK The space is dead. 2381 * KERN_INVALID_NAME The name doesn't denote a right. 2382 * KERN_INVALID_RIGHT The right isn't correct. 2383 * KERN_INVALID_VALUE The delta for send right is incorrect. 2384 * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch. 2385 * This also raises a EXC_GUARD exception. 2386 */ 2387 2388kern_return_t 2389mach_port_destruct( 2390 ipc_space_t space, 2391 mach_port_name_t name, 2392 mach_port_delta_t srdelta, 2393 uint64_t guard) 2394{ 2395 kern_return_t kr; 2396 ipc_entry_t entry; 2397 2398 if (space == IS_NULL) 2399 return KERN_INVALID_TASK; 2400 2401 if (!MACH_PORT_VALID(name)) 2402 return KERN_INVALID_NAME; 2403 2404 /* Remove reference for receive right */ 2405 kr = ipc_right_lookup_write(space, name, &entry); 2406 if (kr != KERN_SUCCESS) 2407 return kr; 2408 /* space is write-locked and active */ 2409 kr = ipc_right_destruct(space, name, entry, srdelta, guard); /* unlocks */ 2410 2411 return kr; 2412} 2413 2414/* 2415 * Routine: mach_port_guard [kernel call] 2416 * Purpose: 2417 * Guard a mach port with specified guard value. 2418 * The context field of the port is used as the guard. 2419 * Conditions: 2420 * None. 2421 * Returns: 2422 * KERN_SUCCESS The name is destroyed. 2423 * KERN_INVALID_TASK The space is null. 2424 * KERN_INVALID_TASK The space is dead. 2425 * KERN_INVALID_NAME The name doesn't denote a right. 2426 * KERN_INVALID_RIGHT The right isn't correct. 2427 * KERN_INVALID_ARGUMENT Port already contains a context/guard. 2428 */ 2429kern_return_t 2430mach_port_guard( 2431 ipc_space_t space, 2432 mach_port_name_t name, 2433 uint64_t guard, 2434 boolean_t strict) 2435{ 2436 kern_return_t kr; 2437 ipc_port_t port; 2438 2439 if (space == IS_NULL) 2440 return KERN_INVALID_TASK; 2441 2442 if (!MACH_PORT_VALID(name)) 2443 return KERN_INVALID_NAME; 2444 2445 /* Guard can be applied only to receive rights */ 2446 kr = ipc_port_translate_receive(space, name, &port); 2447 if (kr != KERN_SUCCESS) 2448 return kr; 2449 2450 /* Port locked and active */ 2451 kr = mach_port_guard_locked(port, guard, strict); 2452 ip_unlock(port); 2453 2454 return kr; 2455 2456} 2457 2458/* 2459 * Routine: mach_port_unguard [kernel call] 2460 * Purpose: 2461 * Unguard a mach port with specified guard value. 2462 * Conditions: 2463 * None. 2464 * Returns: 2465 * KERN_SUCCESS The name is destroyed. 2466 * KERN_INVALID_TASK The space is null. 2467 * KERN_INVALID_TASK The space is dead. 2468 * KERN_INVALID_NAME The name doesn't denote a right. 2469 * KERN_INVALID_RIGHT The right isn't correct. 2470 * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch. 2471 * This also raises a EXC_GUARD exception. 2472 */ 2473kern_return_t 2474mach_port_unguard( 2475 ipc_space_t space, 2476 mach_port_name_t name, 2477 uint64_t guard) 2478{ 2479 2480 kern_return_t kr; 2481 ipc_port_t port; 2482 2483 if (space == IS_NULL) 2484 return KERN_INVALID_TASK; 2485 2486 if (!MACH_PORT_VALID(name)) 2487 return KERN_INVALID_NAME; 2488 2489 kr = ipc_port_translate_receive(space, name, &port); 2490 if (kr != KERN_SUCCESS) 2491 return kr; 2492 2493 /* Port locked and active */ 2494 kr = mach_port_unguard_locked(port, name, guard); 2495 ip_unlock(port); 2496 return kr; 2497} 2498 2499