/ duct-tape / xnu / osfmk / ipc / ipc_object.c
ipc_object.c
   1  /*
   2   * Copyright (c) 2000-2020 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/ipc_object.c
  67   *	Author:	Rich Draves
  68   *	Date:	1989
  69   *
  70   *	Functions to manipulate IPC objects.
  71   */
  72  
  73  #include <mach/mach_types.h>
  74  #include <mach/boolean.h>
  75  #include <mach/kern_return.h>
  76  #include <mach/port.h>
  77  #include <mach/message.h>
  78  
  79  #include <kern/kern_types.h>
  80  #include <kern/misc_protos.h>
  81  #include <kern/ipc_kobject.h>
  82  
  83  #include <ipc/ipc_types.h>
  84  #include <ipc/ipc_importance.h>
  85  #include <ipc/port.h>
  86  #include <ipc/ipc_space.h>
  87  #include <ipc/ipc_entry.h>
  88  #include <ipc/ipc_object.h>
  89  #include <ipc/ipc_hash.h>
  90  #include <ipc/ipc_right.h>
  91  #include <ipc/ipc_notify.h>
  92  #include <ipc/ipc_port.h>
  93  #include <ipc/ipc_pset.h>
  94  
  95  #include <security/mac_mach_internal.h>
  96  
  97  #if DSERVER_EXTENDED_DEBUG
  98  	#include <darlingserver/duct-tape/hooks.internal.h>
  99  	#include <darlingserver/duct-tape/task.h>
 100  #endif
 101  
 102  SECURITY_READ_ONLY_LATE(zone_t) ipc_object_zones[IOT_NUMBER];
 103  
 104  ZONE_INIT(&ipc_object_zones[IOT_PORT], "ipc ports", sizeof(struct ipc_port),
 105      ZC_NOENCRYPT | ZC_CACHING | ZC_ZFREE_CLEARMEM | ZC_NOSEQUESTER,
 106      ZONE_ID_IPC_PORT, NULL);
 107  
 108  ZONE_INIT(&ipc_object_zones[IOT_PORT_SET], "ipc port sets",
 109      sizeof(struct ipc_pset),
 110      ZC_NOENCRYPT | ZC_ZFREE_CLEARMEM | ZC_NOSEQUESTER,
 111      ZONE_ID_IPC_PORT_SET, NULL);
 112  
 113  /*
 114   *	Routine:	ipc_object_reference
 115   *	Purpose:
 116   *		Take a reference to an object.
 117   */
 118  
 119  void
 120  ipc_object_reference(
 121  	ipc_object_t    object)
 122  {
 123  	io_reference(object);
 124  }
 125  
 126  /*
 127   *	Routine:	ipc_object_release
 128   *	Purpose:
 129   *		Release a reference to an object.
 130   */
 131  
 132  void
 133  ipc_object_release(
 134  	ipc_object_t    object)
 135  {
 136  	io_release(object);
 137  }
 138  
 139  /*
 140   *	Routine:	ipc_object_translate
 141   *	Purpose:
 142   *		Look up an object in a space.
 143   *	Conditions:
 144   *		Nothing locked before.  If successful, the object
 145   *		is returned active and locked.  The caller doesn't get a ref.
 146   *	Returns:
 147   *		KERN_SUCCESS		Object returned locked.
 148   *		KERN_INVALID_TASK	The space is dead.
 149   *		KERN_INVALID_NAME	The name doesn't denote a right
 150   *		KERN_INVALID_RIGHT	Name doesn't denote the correct right
 151   */
 152  kern_return_t
 153  ipc_object_translate(
 154  	ipc_space_t             space,
 155  	mach_port_name_t        name,
 156  	mach_port_right_t       right,
 157  	ipc_object_t            *objectp)
 158  {
 159  	ipc_entry_t entry;
 160  	ipc_object_t object;
 161  	kern_return_t kr;
 162  
 163  	if (!MACH_PORT_RIGHT_VALID_TRANSLATE(right)) {
 164  		return KERN_INVALID_RIGHT;
 165  	}
 166  
 167  	kr = ipc_right_lookup_read(space, name, &entry);
 168  	if (kr != KERN_SUCCESS) {
 169  		return kr;
 170  	}
 171  	/* space is read-locked and active */
 172  
 173  	if ((entry->ie_bits & MACH_PORT_TYPE(right)) == MACH_PORT_TYPE_NONE) {
 174  		is_read_unlock(space);
 175  		return KERN_INVALID_RIGHT;
 176  	}
 177  
 178  	object = entry->ie_object;
 179  	assert(object != IO_NULL);
 180  
 181  	io_lock(object);
 182  	is_read_unlock(space);
 183  
 184  	if (!io_active(object)) {
 185  		io_unlock(object);
 186  		return KERN_INVALID_NAME;
 187  	}
 188  
 189  	*objectp = object;
 190  	return KERN_SUCCESS;
 191  }
 192  
 193  /*
 194   *	Routine:	ipc_object_translate_two
 195   *	Purpose:
 196   *		Look up two objects in a space.
 197   *	Conditions:
 198   *		Nothing locked before.  If successful, the objects
 199   *		are returned locked.  The caller doesn't get a ref.
 200   *	Returns:
 201   *		KERN_SUCCESS		Objects returned locked.
 202   *		KERN_INVALID_TASK	The space is dead.
 203   *		KERN_INVALID_NAME	A name doesn't denote a right.
 204   *		KERN_INVALID_RIGHT	A name doesn't denote the correct right.
 205   */
 206  
 207  kern_return_t
 208  ipc_object_translate_two(
 209  	ipc_space_t             space,
 210  	mach_port_name_t        name1,
 211  	mach_port_right_t       right1,
 212  	ipc_object_t            *objectp1,
 213  	mach_port_name_t        name2,
 214  	mach_port_right_t       right2,
 215  	ipc_object_t            *objectp2)
 216  {
 217  	ipc_entry_t entry1;
 218  	ipc_entry_t entry2;
 219  	ipc_object_t object1, object2;
 220  	kern_return_t kr;
 221  	boolean_t doguard = TRUE;
 222  
 223  	kr = ipc_right_lookup_two_read(space, name1, &entry1, name2, &entry2);
 224  	if (kr != KERN_SUCCESS) {
 225  		return kr;
 226  	}
 227  	/* space is read-locked and active */
 228  
 229  	if ((entry1->ie_bits & MACH_PORT_TYPE(right1)) == MACH_PORT_TYPE_NONE) {
 230  		/* If looking for receive, and the entry used to hold one, give a pass on EXC_GUARD */
 231  		if ((right1 & MACH_PORT_RIGHT_RECEIVE) == MACH_PORT_RIGHT_RECEIVE &&
 232  		    (entry1->ie_bits & MACH_PORT_TYPE_EX_RECEIVE) == MACH_PORT_TYPE_EX_RECEIVE) {
 233  			doguard = FALSE;
 234  		}
 235  		is_read_unlock(space);
 236  		if (doguard) {
 237  			mach_port_guard_exception(name1, 0, 0, kGUARD_EXC_INVALID_RIGHT);
 238  		}
 239  		return KERN_INVALID_RIGHT;
 240  	}
 241  
 242  	if ((entry2->ie_bits & MACH_PORT_TYPE(right2)) == MACH_PORT_TYPE_NONE) {
 243  		/* If looking for receive, and the entry used to hold one, give a pass on EXC_GUARD */
 244  		if ((right2 & MACH_PORT_RIGHT_RECEIVE) == MACH_PORT_RIGHT_RECEIVE &&
 245  		    (entry2->ie_bits & MACH_PORT_TYPE_EX_RECEIVE) == MACH_PORT_TYPE_EX_RECEIVE) {
 246  			doguard = FALSE;
 247  		}
 248  		is_read_unlock(space);
 249  		if (doguard) {
 250  			mach_port_guard_exception(name2, 0, 0, kGUARD_EXC_INVALID_RIGHT);
 251  		}
 252  		return KERN_INVALID_RIGHT;
 253  	}
 254  
 255  	object1 = entry1->ie_object;
 256  	assert(object1 != IO_NULL);
 257  	io_lock(object1);
 258  	if (!io_active(object1)) {
 259  		io_unlock(object1);
 260  		is_read_unlock(space);
 261  		return KERN_INVALID_NAME;
 262  	}
 263  
 264  	object2 = entry2->ie_object;
 265  	assert(object2 != IO_NULL);
 266  	io_lock(object2);
 267  	if (!io_active(object2)) {
 268  		io_unlock(object1);
 269  		io_unlock(object2);
 270  		is_read_unlock(space);
 271  		return KERN_INVALID_NAME;
 272  	}
 273  
 274  	*objectp1 = object1;
 275  	*objectp2 = object2;
 276  
 277  	is_read_unlock(space);
 278  	return KERN_SUCCESS;
 279  }
 280  
 281  /*
 282   *	Routine:	ipc_object_alloc_dead
 283   *	Purpose:
 284   *		Allocate a dead-name entry.
 285   *	Conditions:
 286   *		Nothing locked.
 287   *	Returns:
 288   *		KERN_SUCCESS		The dead name is allocated.
 289   *		KERN_INVALID_TASK	The space is dead.
 290   *		KERN_NO_SPACE		No room for an entry in the space.
 291   *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
 292   */
 293  
 294  kern_return_t
 295  ipc_object_alloc_dead(
 296  	ipc_space_t             space,
 297  	mach_port_name_t        *namep)
 298  {
 299  	ipc_entry_t entry;
 300  	kern_return_t kr;
 301  
 302  	kr = ipc_entry_alloc(space, namep, &entry);
 303  	if (kr != KERN_SUCCESS) {
 304  		return kr;
 305  	}
 306  	/* space is write-locked */
 307  
 308  	/* null object, MACH_PORT_TYPE_DEAD_NAME, 1 uref */
 309  
 310  	assert(entry->ie_object == IO_NULL);
 311  	entry->ie_bits |= MACH_PORT_TYPE_DEAD_NAME | 1;
 312  	ipc_entry_modified(space, *namep, entry);
 313  	is_write_unlock(space);
 314  	return KERN_SUCCESS;
 315  }
 316  
 317  /*
 318   *	Routine:	ipc_object_alloc_dead_name
 319   *	Purpose:
 320   *		Allocate a dead-name entry, with a specific name.
 321   *	Conditions:
 322   *		Nothing locked.
 323   *	Returns:
 324   *		KERN_SUCCESS		The dead name is allocated.
 325   *		KERN_INVALID_TASK	The space is dead.
 326   *		KERN_NAME_EXISTS	The name already denotes a right.
 327   *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
 328   */
 329  
 330  kern_return_t
 331  ipc_object_alloc_dead_name(
 332  	ipc_space_t             space,
 333  	mach_port_name_t        name)
 334  {
 335  	ipc_entry_t entry;
 336  	kern_return_t kr;
 337  
 338  	kr = ipc_entry_alloc_name(space, name, &entry);
 339  	if (kr != KERN_SUCCESS) {
 340  		return kr;
 341  	}
 342  	/* space is write-locked */
 343  
 344  	if (ipc_right_inuse(entry)) {
 345  		is_write_unlock(space);
 346  		return KERN_NAME_EXISTS;
 347  	}
 348  
 349  	/* null object, MACH_PORT_TYPE_DEAD_NAME, 1 uref */
 350  
 351  	assert(entry->ie_object == IO_NULL);
 352  	entry->ie_bits |= MACH_PORT_TYPE_DEAD_NAME | 1;
 353  	ipc_entry_modified(space, name, entry);
 354  	is_write_unlock(space);
 355  	return KERN_SUCCESS;
 356  }
 357  
 358  /*
 359   *	Routine:	ipc_object_alloc
 360   *	Purpose:
 361   *		Allocate an object.
 362   *	Conditions:
 363   *		Nothing locked.  If successful, the object is returned locked.
 364   *		The space is write locked on successful return.
 365   *		The caller doesn't get a reference for the object.
 366   *	Returns:
 367   *		KERN_SUCCESS		The object is allocated.
 368   *		KERN_INVALID_TASK	The space is dead.
 369   *		KERN_NO_SPACE		No room for an entry in the space.
 370   *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
 371   */
 372  
 373  kern_return_t
 374  ipc_object_alloc(
 375  	ipc_space_t             space,
 376  	ipc_object_type_t       otype,
 377  	mach_port_type_t        type,
 378  	mach_port_urefs_t       urefs,
 379  	mach_port_name_t        *namep,
 380  	ipc_object_t            *objectp)
 381  {
 382  	ipc_object_t object;
 383  	ipc_entry_t entry;
 384  	kern_return_t kr;
 385  
 386  	assert(otype < IOT_NUMBER);
 387  	assert((type & MACH_PORT_TYPE_ALL_RIGHTS) == type);
 388  	assert(type != MACH_PORT_TYPE_NONE);
 389  	assert(urefs <= MACH_PORT_UREFS_MAX);
 390  
 391  	object = io_alloc(otype, Z_WAITOK | Z_ZERO);
 392  	if (object == IO_NULL) {
 393  		return KERN_RESOURCE_SHORTAGE;
 394  	}
 395  
 396  	io_lock_init(object);
 397  	*namep = CAST_MACH_PORT_TO_NAME(object);
 398  	kr = ipc_entry_alloc(space, namep, &entry);
 399  	if (kr != KERN_SUCCESS) {
 400  		io_free(otype, object);
 401  		return kr;
 402  	}
 403  	/* space is write-locked */
 404  
 405  	entry->ie_bits |= type | urefs;
 406  	entry->ie_object = object;
 407  	ipc_entry_modified(space, *namep, entry);
 408  
 409  	object->io_bits = io_makebits(TRUE, otype, 0);
 410  	io_lock(object);
 411  
 412  	object->io_references = 1; /* for entry, not caller */
 413  
 414  #if DSERVER_EXTENDED_DEBUG
 415  	dtape_hooks->task_register_name(dtape_task_for_xnu_task(current_task())->context, *namep, (uintptr_t)object);
 416  #endif
 417  
 418  	*objectp = object;
 419  	return KERN_SUCCESS;
 420  }
 421  
 422  /*
 423   *	Routine:	ipc_object_alloc_name
 424   *	Purpose:
 425   *		Allocate an object, with a specific name.
 426   *	Conditions:
 427   *		Nothing locked.  If successful, the object is returned locked.
 428   *		The caller doesn't get a reference for the object.
 429   *	Returns:
 430   *		KERN_SUCCESS		The object is allocated.
 431   *		KERN_INVALID_TASK	The space is dead.
 432   *		KERN_NAME_EXISTS	The name already denotes a right.
 433   *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
 434   */
 435  
 436  kern_return_t
 437  ipc_object_alloc_name(
 438  	ipc_space_t             space,
 439  	ipc_object_type_t       otype,
 440  	mach_port_type_t        type,
 441  	mach_port_urefs_t       urefs,
 442  	mach_port_name_t        name,
 443  	ipc_object_t            *objectp)
 444  {
 445  	ipc_object_t object;
 446  	ipc_entry_t entry;
 447  	kern_return_t kr;
 448  
 449  	assert(otype < IOT_NUMBER);
 450  	assert((type & MACH_PORT_TYPE_ALL_RIGHTS) == type);
 451  	assert(type != MACH_PORT_TYPE_NONE);
 452  	assert(urefs <= MACH_PORT_UREFS_MAX);
 453  
 454  	object = io_alloc(otype, Z_WAITOK | Z_ZERO);
 455  	if (object == IO_NULL) {
 456  		return KERN_RESOURCE_SHORTAGE;
 457  	}
 458  
 459  	io_lock_init(object);
 460  	kr = ipc_entry_alloc_name(space, name, &entry);
 461  	if (kr != KERN_SUCCESS) {
 462  		io_free(otype, object);
 463  		return kr;
 464  	}
 465  	/* space is write-locked */
 466  
 467  	if (ipc_right_inuse(entry)) {
 468  		is_write_unlock(space);
 469  		io_free(otype, object);
 470  		return KERN_NAME_EXISTS;
 471  	}
 472  
 473  	entry->ie_bits |= type | urefs;
 474  	entry->ie_object = object;
 475  	ipc_entry_modified(space, name, entry);
 476  
 477  	object->io_bits = io_makebits(TRUE, otype, 0);
 478  
 479  	io_lock(object);
 480  	is_write_unlock(space);
 481  
 482  	object->io_references = 1; /* for entry, not caller */
 483  
 484  	*objectp = object;
 485  	return KERN_SUCCESS;
 486  }
 487  
 488  /*	Routine:	ipc_object_validate
 489   *	Purpose:
 490   *		Validates an ipc port or port set as belonging to the correct
 491   *		zone.
 492   */
 493  
 494  void
 495  ipc_object_validate(
 496  	ipc_object_t    object)
 497  {
 498  	if (io_otype(object) != IOT_PORT_SET) {
 499  		zone_id_require(ZONE_ID_IPC_PORT,
 500  		    sizeof(struct ipc_port), object);
 501  	} else {
 502  		zone_id_require(ZONE_ID_IPC_PORT_SET,
 503  		    sizeof(struct ipc_pset), object);
 504  	}
 505  }
 506  
 507  /*
 508   *	Routine:	ipc_object_copyin_type
 509   *	Purpose:
 510   *		Convert a send type name to a received type name.
 511   */
 512  
 513  mach_msg_type_name_t
 514  ipc_object_copyin_type(
 515  	mach_msg_type_name_t    msgt_name)
 516  {
 517  	switch (msgt_name) {
 518  	case MACH_MSG_TYPE_MOVE_RECEIVE:
 519  		return MACH_MSG_TYPE_PORT_RECEIVE;
 520  
 521  	case MACH_MSG_TYPE_MOVE_SEND_ONCE:
 522  	case MACH_MSG_TYPE_MAKE_SEND_ONCE:
 523  		return MACH_MSG_TYPE_PORT_SEND_ONCE;
 524  
 525  	case MACH_MSG_TYPE_MOVE_SEND:
 526  	case MACH_MSG_TYPE_MAKE_SEND:
 527  	case MACH_MSG_TYPE_COPY_SEND:
 528  		return MACH_MSG_TYPE_PORT_SEND;
 529  
 530  	case MACH_MSG_TYPE_DISPOSE_RECEIVE:
 531  	case MACH_MSG_TYPE_DISPOSE_SEND:
 532  	case MACH_MSG_TYPE_DISPOSE_SEND_ONCE:
 533  	/* fall thru */
 534  	default:
 535  		return MACH_MSG_TYPE_PORT_NONE;
 536  	}
 537  }
 538  
 539  /*
 540   *	Routine:	ipc_object_copyin
 541   *	Purpose:
 542   *		Copyin a capability from a space.
 543   *		If successful, the caller gets a ref
 544   *		for the resulting object, unless it is IO_DEAD.
 545   *	Conditions:
 546   *		Nothing locked.
 547   *	Returns:
 548   *		KERN_SUCCESS		Acquired an object, possibly IO_DEAD.
 549   *		KERN_INVALID_TASK	The space is dead.
 550   *		KERN_INVALID_NAME	Name doesn't exist in space.
 551   *		KERN_INVALID_RIGHT	Name doesn't denote correct right.
 552   */
 553  
 554  kern_return_t
 555  ipc_object_copyin(
 556  	ipc_space_t                space,
 557  	mach_port_name_t           name,
 558  	mach_msg_type_name_t       msgt_name,
 559  	ipc_object_t               *objectp,
 560  	mach_port_context_t        context,
 561  	mach_msg_guard_flags_t     *guard_flags,
 562  	ipc_object_copyin_flags_t  copyin_flags)
 563  {
 564  	ipc_entry_t entry;
 565  	ipc_port_t soright;
 566  	ipc_port_t release_port;
 567  	kern_return_t kr;
 568  	int assertcnt = 0;
 569  
 570  	ipc_object_copyin_flags_t irc_flags = IPC_OBJECT_COPYIN_FLAGS_ALLOW_IMMOVABLE_SEND |
 571  	    IPC_OBJECT_COPYIN_FLAGS_SOFT_FAIL_IMMOVABLE_SEND;
 572  	irc_flags = (copyin_flags & irc_flags) | IPC_OBJECT_COPYIN_FLAGS_DEADOK;
 573  	/*
 574  	 *	Could first try a read lock when doing
 575  	 *	MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND,
 576  	 *	and MACH_MSG_TYPE_MAKE_SEND_ONCE.
 577  	 */
 578  
 579  	kr = ipc_right_lookup_write(space, name, &entry);
 580  	if (kr != KERN_SUCCESS) {
 581  		return kr;
 582  	}
 583  	/* space is write-locked and active */
 584  
 585  	release_port = IP_NULL;
 586  	kr = ipc_right_copyin(space, name, entry,
 587  	    msgt_name, irc_flags,
 588  	    objectp, &soright,
 589  	    &release_port,
 590  	    &assertcnt,
 591  	    context,
 592  	    guard_flags);
 593  	if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE) {
 594  		ipc_entry_dealloc(space, name, entry);
 595  	}
 596  	is_write_unlock(space);
 597  
 598  #if IMPORTANCE_INHERITANCE
 599  	if (0 < assertcnt && ipc_importance_task_is_any_receiver_type(current_task()->task_imp_base)) {
 600  		ipc_importance_task_drop_internal_assertion(current_task()->task_imp_base, assertcnt);
 601  	}
 602  #endif /* IMPORTANCE_INHERITANCE */
 603  
 604  	if (release_port != IP_NULL) {
 605  		ip_release(release_port);
 606  	}
 607  
 608  	if ((kr == KERN_SUCCESS) && (soright != IP_NULL)) {
 609  		ipc_notify_port_deleted(soright, name);
 610  	}
 611  
 612  	return kr;
 613  }
 614  
 615  /*
 616   *	Routine:	ipc_object_copyin_from_kernel
 617   *	Purpose:
 618   *		Copyin a naked capability from the kernel.
 619   *
 620   *		MACH_MSG_TYPE_MOVE_RECEIVE
 621   *			The receiver must be ipc_space_kernel
 622   *			or the receive right must already be in limbo.
 623   *			Consumes the naked receive right.
 624   *		MACH_MSG_TYPE_COPY_SEND
 625   *			A naked send right must be supplied.
 626   *			The port gains a reference, and a send right
 627   *			if the port is still active.
 628   *		MACH_MSG_TYPE_MAKE_SEND
 629   *			The receiver must be ipc_space_kernel.
 630   *			The port gains a reference and a send right.
 631   *		MACH_MSG_TYPE_MOVE_SEND
 632   *			Consumes a naked send right.
 633   *		MACH_MSG_TYPE_MAKE_SEND_ONCE
 634   *			The port gains a reference and a send-once right.
 635   *			Receiver also be the caller of device subsystem,
 636   *			so no assertion.
 637   *		MACH_MSG_TYPE_MOVE_SEND_ONCE
 638   *			Consumes a naked send-once right.
 639   *	Conditions:
 640   *		Nothing locked.
 641   */
 642  
 643  void
 644  ipc_object_copyin_from_kernel(
 645  	ipc_object_t            object,
 646  	mach_msg_type_name_t    msgt_name)
 647  {
 648  	assert(IO_VALID(object));
 649  
 650  	switch (msgt_name) {
 651  	case MACH_MSG_TYPE_MOVE_RECEIVE: {
 652  		ipc_port_t port = ip_object_to_port(object);
 653  
 654  		ip_lock(port);
 655  		imq_lock(&port->ip_messages);
 656  		require_ip_active(port);
 657  		if (port->ip_destination != IP_NULL) {
 658  			assert(port->ip_receiver == ipc_space_kernel);
 659  			assert(port->ip_immovable_receive == 0);
 660  
 661  			/* relevant part of ipc_port_clear_receiver */
 662  			port->ip_mscount = 0;
 663  			port->ip_receiver_name = MACH_PORT_NULL;
 664  			port->ip_destination = IP_NULL;
 665  		}
 666  		imq_unlock(&port->ip_messages);
 667  		ip_unlock(port);
 668  		break;
 669  	}
 670  
 671  	case MACH_MSG_TYPE_COPY_SEND: {
 672  		ipc_port_t port = ip_object_to_port(object);
 673  
 674  		ip_lock(port);
 675  		if (ip_active(port)) {
 676  			assert(port->ip_srights > 0);
 677  		}
 678  		port->ip_srights++;
 679  		ip_reference(port);
 680  		ip_unlock(port);
 681  		break;
 682  	}
 683  
 684  	case MACH_MSG_TYPE_MAKE_SEND: {
 685  		ipc_port_t port = ip_object_to_port(object);
 686  
 687  		ip_lock(port);
 688  		if (ip_active(port)) {
 689  			assert(port->ip_receiver_name != MACH_PORT_NULL);
 690  			assert((port->ip_receiver == ipc_space_kernel) ||
 691  			    (port->ip_receiver->is_node_id != HOST_LOCAL_NODE));
 692  			port->ip_mscount++;
 693  		}
 694  
 695  		port->ip_srights++;
 696  		ip_reference(port);
 697  		ip_unlock(port);
 698  		break;
 699  	}
 700  
 701  	case MACH_MSG_TYPE_MOVE_SEND: {
 702  		/* move naked send right into the message */
 703  		assert(ip_object_to_port(object)->ip_srights);
 704  		break;
 705  	}
 706  
 707  	case MACH_MSG_TYPE_MAKE_SEND_ONCE: {
 708  		ipc_port_t port = ip_object_to_port(object);
 709  
 710  		ip_lock(port);
 711  		if (ip_active(port)) {
 712  			assert(port->ip_receiver_name != MACH_PORT_NULL);
 713  		}
 714  		ipc_port_make_sonce_locked(port);
 715  		ip_unlock(port);
 716  		break;
 717  	}
 718  
 719  	case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
 720  		/* move naked send-once right into the message */
 721  		assert(ip_object_to_port(object)->ip_sorights);
 722  		break;
 723  	}
 724  
 725  	default:
 726  		panic("ipc_object_copyin_from_kernel: strange rights");
 727  	}
 728  }
 729  
 730  /*
 731   *	Routine:	ipc_object_destroy
 732   *	Purpose:
 733   *		Destroys a naked capability.
 734   *		Consumes a ref for the object.
 735   *
 736   *		A receive right should be in limbo or in transit.
 737   *	Conditions:
 738   *		Nothing locked.
 739   */
 740  
 741  void
 742  ipc_object_destroy(
 743  	ipc_object_t            object,
 744  	mach_msg_type_name_t    msgt_name)
 745  {
 746  	assert(IO_VALID(object));
 747  	assert(io_otype(object) == IOT_PORT);
 748  
 749  	switch (msgt_name) {
 750  	case MACH_MSG_TYPE_PORT_SEND:
 751  		ipc_port_release_send(ip_object_to_port(object));
 752  		break;
 753  
 754  	case MACH_MSG_TYPE_PORT_SEND_ONCE:
 755  		ipc_notify_send_once(ip_object_to_port(object));
 756  		break;
 757  
 758  	case MACH_MSG_TYPE_PORT_RECEIVE:
 759  		ipc_port_release_receive(ip_object_to_port(object));
 760  		break;
 761  
 762  	default:
 763  		panic("ipc_object_destroy: strange rights");
 764  	}
 765  }
 766  
 767  /*
 768   *	Routine:	ipc_object_destroy_dest
 769   *	Purpose:
 770   *		Destroys a naked capability for the destination of
 771   *		of a message. Consumes a ref for the object.
 772   *
 773   *	Conditions:
 774   *		Nothing locked.
 775   */
 776  
 777  void
 778  ipc_object_destroy_dest(
 779  	ipc_object_t            object,
 780  	mach_msg_type_name_t    msgt_name)
 781  {
 782  	assert(IO_VALID(object));
 783  	assert(io_otype(object) == IOT_PORT);
 784  
 785  	switch (msgt_name) {
 786  	case MACH_MSG_TYPE_PORT_SEND:
 787  		ipc_port_release_send(ip_object_to_port(object));
 788  		break;
 789  
 790  	case MACH_MSG_TYPE_PORT_SEND_ONCE:
 791  		if (io_active(object) &&
 792  		    !ip_full_kernel(ip_object_to_port(object))) {
 793  			ipc_notify_send_once(ip_object_to_port(object));
 794  		} else {
 795  			ipc_port_release_sonce(ip_object_to_port(object));
 796  		}
 797  		break;
 798  
 799  	default:
 800  		panic("ipc_object_destroy_dest: strange rights");
 801  	}
 802  }
 803  
 804  /*
 805   *	Routine:	ipc_object_insert_send_right
 806   *	Purpose:
 807   *		Insert a send right into an object already in the space.
 808   *		The specified name must already point to a valid object.
 809   *
 810   *		Note: This really is a combined copyin()/copyout(),
 811   *		that avoids most of the overhead of being implemented that way.
 812   *
 813   *		This is the fastpath for mach_port_insert_right.
 814   *
 815   *	Conditions:
 816   *		Nothing locked.
 817   *
 818   *		msgt_name must be MACH_MSG_TYPE_MAKE_SEND_ONCE or
 819   *		MACH_MSG_TYPE_MOVE_SEND_ONCE.
 820   *
 821   *	Returns:
 822   *		KERN_SUCCESS		Copied out object, consumed ref.
 823   *		KERN_INVALID_TASK	The space is dead.
 824   *		KERN_INVALID_NAME	Name doesn't exist in space.
 825   *		KERN_INVALID_CAPABILITY	The object is dead.
 826   *		KERN_RIGHT_EXISTS	Space has rights under another name.
 827   */
 828  kern_return_t
 829  ipc_object_insert_send_right(
 830  	ipc_space_t             space,
 831  	mach_port_name_t        name,
 832  	mach_msg_type_name_t    msgt_name)
 833  {
 834  	ipc_entry_bits_t bits;
 835  	ipc_object_t object;
 836  	ipc_entry_t entry;
 837  	kern_return_t kr;
 838  
 839  	assert(msgt_name == MACH_MSG_TYPE_MAKE_SEND ||
 840  	    msgt_name == MACH_MSG_TYPE_COPY_SEND);
 841  
 842  	kr = ipc_right_lookup_write(space, name, &entry);
 843  	if (kr != KERN_SUCCESS) {
 844  		return kr;
 845  	}
 846  	/* space is write-locked and active */
 847  
 848  	if (!IO_VALID(entry->ie_object)) {
 849  		is_write_unlock(space);
 850  		return KERN_INVALID_CAPABILITY;
 851  	}
 852  
 853  	bits = entry->ie_bits;
 854  	object = entry->ie_object;
 855  
 856  	io_lock(object);
 857  	if (!io_active(object)) {
 858  		kr = KERN_INVALID_CAPABILITY;
 859  	} else if (msgt_name == MACH_MSG_TYPE_MAKE_SEND) {
 860  		if (bits & MACH_PORT_TYPE_RECEIVE) {
 861  			ipc_port_t port = ip_object_to_port(object);
 862  			port->ip_mscount++;
 863  			if ((bits & MACH_PORT_TYPE_SEND) == 0) {
 864  				port->ip_srights++;
 865  				bits |= MACH_PORT_TYPE_SEND;
 866  			}
 867  			/* leave urefs pegged to maximum if it overflowed */
 868  			if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
 869  				bits += 1; /* increment urefs */
 870  			}
 871  			entry->ie_bits = bits;
 872  			ipc_entry_modified(space, name, entry);
 873  			kr = KERN_SUCCESS;
 874  		} else {
 875  			kr = KERN_INVALID_RIGHT;
 876  		}
 877  	} else { // MACH_MSG_TYPE_COPY_SEND
 878  		if (bits & MACH_PORT_TYPE_SEND) {
 879  			/* leave urefs pegged to maximum if it overflowed */
 880  			if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
 881  				entry->ie_bits = bits + 1; /* increment urefs */
 882  			}
 883  			ipc_entry_modified(space, name, entry);
 884  			kr = KERN_SUCCESS;
 885  		} else {
 886  			kr = KERN_INVALID_RIGHT;
 887  		}
 888  	}
 889  
 890  	io_unlock(object);
 891  	is_write_unlock(space);
 892  
 893  	return kr;
 894  }
 895  
 896  /*
 897   *	Routine:	ipc_object_copyout
 898   *	Purpose:
 899   *		Copyout a capability, placing it into a space.
 900   *		Always consumes a ref for the object.
 901   *	Conditions:
 902   *		Nothing locked.
 903   *	Returns:
 904   *		KERN_SUCCESS		Copied out object, consumed ref.
 905   *		KERN_INVALID_TASK	The space is dead.
 906   *		KERN_INVALID_CAPABILITY	The object is dead.
 907   *		KERN_NO_SPACE		No room in space for another right.
 908   *		KERN_RESOURCE_SHORTAGE	No memory available.
 909   *		KERN_UREFS_OVERFLOW	Urefs limit exceeded
 910   *			and overflow wasn't specified.
 911   */
 912  
 913  kern_return_t
 914  ipc_object_copyout(
 915  	ipc_space_t             space,
 916  	ipc_object_t            object,
 917  	mach_msg_type_name_t    msgt_name,
 918  	ipc_object_copyout_flags_t flags,
 919  	mach_port_context_t     *context,
 920  	mach_msg_guard_flags_t  *guard_flags,
 921  	mach_port_name_t        *namep)
 922  {
 923  	struct knote *kn = current_thread()->ith_knote;
 924  	mach_port_name_t name;
 925  	ipc_port_t port = ip_object_to_port(object);
 926  	ipc_entry_t entry;
 927  	kern_return_t kr;
 928  
 929  	assert(IO_VALID(object));
 930  	assert(io_otype(object) == IOT_PORT);
 931  
 932  	if (ITH_KNOTE_VALID(kn, msgt_name)) {
 933  		filt_machport_turnstile_prepare_lazily(kn, msgt_name, port);
 934  	}
 935  
 936  	is_write_lock(space);
 937  
 938  	for (;;) {
 939  		ipc_port_t port_subst = IP_NULL;
 940  
 941  		if (!is_active(space)) {
 942  			is_write_unlock(space);
 943  			kr = KERN_INVALID_TASK;
 944  			goto out;
 945  		}
 946  
 947  		kr = ipc_entries_hold(space, 1);
 948  		if (kr != KERN_SUCCESS) {
 949  			/* unlocks/locks space, so must start again */
 950  
 951  			kr = ipc_entry_grow_table(space, ITS_SIZE_NONE);
 952  			if (kr != KERN_SUCCESS) {
 953  				/* space is unlocked */
 954  				goto out;
 955  			}
 956  			continue;
 957  		}
 958  
 959  		io_lock(object);
 960  		if (!io_active(object)) {
 961  			io_unlock(object);
 962  			is_write_unlock(space);
 963  			kr = KERN_INVALID_CAPABILITY;
 964  			goto out;
 965  		}
 966  
 967  		/* Don't actually copyout rights we aren't allowed to */
 968  		if (!ip_label_check(space, port, msgt_name, &flags, &port_subst)) {
 969  			io_unlock(object);
 970  			is_write_unlock(space);
 971  			assert(port_subst == IP_NULL);
 972  			kr = KERN_INVALID_CAPABILITY;
 973  			goto out;
 974  		}
 975  
 976  		/* is the kolabel requesting a substitution */
 977  		if (port_subst != IP_NULL) {
 978  			/*
 979  			 * port is unlocked, its right consumed
 980  			 * space is unlocked
 981  			 */
 982  			assert(msgt_name == MACH_MSG_TYPE_PORT_SEND);
 983  			port = port_subst;
 984  			if (!IP_VALID(port)) {
 985  				object = IO_DEAD;
 986  				kr = KERN_INVALID_CAPABILITY;
 987  				goto out;
 988  			}
 989  
 990  			object = ip_to_object(port);
 991  			is_write_lock(space);
 992  			continue;
 993  		}
 994  
 995  		break;
 996  	}
 997  
 998  	/* space is write-locked and active, object is locked and active */
 999  
1000  	if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
1001  	    ipc_right_reverse(space, object, &name, &entry)) {
1002  		assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
1003  	} else {
1004  		ipc_entry_claim(space, &name, &entry);
1005  
1006  		assert(!ipc_right_inuse(entry));
1007  		assert(entry->ie_object == IO_NULL);
1008  
1009  		entry->ie_object = object;
1010  	}
1011  
1012  	kr = ipc_right_copyout(space, name, entry,
1013  	    msgt_name, flags, context, guard_flags, object);
1014  
1015  	/* object is unlocked */
1016  	is_write_unlock(space);
1017  
1018  out:
1019  	if (kr == KERN_SUCCESS) {
1020  		*namep = name;
1021  	} else if (IO_VALID(object)) {
1022  		ipc_object_destroy(object, msgt_name);
1023  	}
1024  
1025  	return kr;
1026  }
1027  
1028  /*
1029   *	Routine:	ipc_object_copyout_name
1030   *	Purpose:
1031   *		Copyout a capability, placing it into a space.
1032   *		The specified name is used for the capability.
1033   *		If successful, consumes a ref for the object.
1034   *	Conditions:
1035   *		Nothing locked.
1036   *	Returns:
1037   *		KERN_SUCCESS		Copied out object, consumed ref.
1038   *		KERN_INVALID_TASK	The space is dead.
1039   *		KERN_INVALID_CAPABILITY	The object is dead.
1040   *		KERN_RESOURCE_SHORTAGE	No memory available.
1041   *		KERN_UREFS_OVERFLOW	Urefs limit exceeded
1042   *			and overflow wasn't specified.
1043   *		KERN_RIGHT_EXISTS	Space has rights under another name.
1044   *		KERN_NAME_EXISTS	Name is already used.
1045   */
1046  
1047  kern_return_t
1048  ipc_object_copyout_name(
1049  	ipc_space_t             space,
1050  	ipc_object_t            object,
1051  	mach_msg_type_name_t    msgt_name,
1052  	mach_port_name_t        name)
1053  {
1054  	ipc_port_t port = ip_object_to_port(object);
1055  	mach_port_name_t oname;
1056  	ipc_entry_t oentry;
1057  	ipc_entry_t entry;
1058  	kern_return_t kr;
1059  
1060  #if IMPORTANCE_INHERITANCE
1061  	int assertcnt = 0;
1062  	ipc_importance_task_t task_imp = IIT_NULL;
1063  #endif /* IMPORTANCE_INHERITANCE */
1064  
1065  	assert(IO_VALID(object));
1066  	assert(io_otype(object) == IOT_PORT);
1067  
1068  	kr = ipc_entry_alloc_name(space, name, &entry);
1069  	if (kr != KERN_SUCCESS) {
1070  		return kr;
1071  	}
1072  	/* space is write-locked and active */
1073  
1074  	io_lock(object);
1075  
1076  	/*
1077  	 * Don't actually copyout rights we aren't allowed to
1078  	 *
1079  	 * In particular, kolabel-ed objects do not allow callers
1080  	 * to pick the name they end up with.
1081  	 */
1082  	if (!io_active(object) || ip_is_kolabeled(port)) {
1083  		io_unlock(object);
1084  		if (!ipc_right_inuse(entry)) {
1085  			ipc_entry_dealloc(space, name, entry);
1086  		}
1087  		is_write_unlock(space);
1088  		return KERN_INVALID_CAPABILITY;
1089  	}
1090  
1091  	/* space is write-locked and active, object is locked and active */
1092  
1093  	if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
1094  	    ipc_right_reverse(space, object, &oname, &oentry)) {
1095  		if (name != oname) {
1096  			io_unlock(object);
1097  			if (!ipc_right_inuse(entry)) {
1098  				ipc_entry_dealloc(space, name, entry);
1099  			}
1100  			is_write_unlock(space);
1101  			return KERN_RIGHT_EXISTS;
1102  		}
1103  
1104  		assert(entry == oentry);
1105  		assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
1106  	} else if (ipc_right_inuse(entry)) {
1107  		io_unlock(object);
1108  		is_write_unlock(space);
1109  		return KERN_NAME_EXISTS;
1110  	} else {
1111  		assert(entry->ie_object == IO_NULL);
1112  
1113  		entry->ie_object = object;
1114  	}
1115  
1116  #if IMPORTANCE_INHERITANCE
1117  	/*
1118  	 * We are slamming a receive right into the space, without
1119  	 * first having been enqueued on a port destined there.  So,
1120  	 * we have to arrange to boost the task appropriately if this
1121  	 * port has assertions (and the task wants them).
1122  	 */
1123  	if (msgt_name == MACH_MSG_TYPE_PORT_RECEIVE) {
1124  		if (space->is_task != TASK_NULL) {
1125  			task_imp = space->is_task->task_imp_base;
1126  			if (ipc_importance_task_is_any_receiver_type(task_imp)) {
1127  				assertcnt = port->ip_impcount;
1128  				ipc_importance_task_reference(task_imp);
1129  			} else {
1130  				task_imp = IIT_NULL;
1131  			}
1132  		}
1133  
1134  		/* take port out of limbo */
1135  		assert(port->ip_tempowner != 0);
1136  		port->ip_tempowner = 0;
1137  	}
1138  
1139  #endif /* IMPORTANCE_INHERITANCE */
1140  
1141  	kr = ipc_right_copyout(space, name, entry,
1142  	    msgt_name, IPC_OBJECT_COPYOUT_FLAGS_NONE, NULL, NULL, object);
1143  
1144  	/* object is unlocked */
1145  	is_write_unlock(space);
1146  
1147  #if IMPORTANCE_INHERITANCE
1148  	/*
1149  	 * Add the assertions to the task that we captured before
1150  	 */
1151  	if (task_imp != IIT_NULL) {
1152  		ipc_importance_task_hold_internal_assertion(task_imp, assertcnt);
1153  		ipc_importance_task_release(task_imp);
1154  	}
1155  #endif /* IMPORTANCE_INHERITANCE */
1156  
1157  	return kr;
1158  }
1159  
1160  /*
1161   *	Routine:	ipc_object_copyout_dest
1162   *	Purpose:
1163   *		Translates/consumes the destination right of a message.
1164   *		This is unlike normal copyout because the right is consumed
1165   *		in a funny way instead of being given to the receiving space.
1166   *		The receiver gets his name for the port, if he has receive
1167   *		rights, otherwise MACH_PORT_NULL.
1168   *	Conditions:
1169   *		The object is locked and active.  Nothing else locked.
1170   *		The object is unlocked and loses a reference.
1171   */
1172  
1173  void
1174  ipc_object_copyout_dest(
1175  	ipc_space_t             space,
1176  	ipc_object_t            object,
1177  	mach_msg_type_name_t    msgt_name,
1178  	mach_port_name_t        *namep)
1179  {
1180  	mach_port_name_t name;
1181  
1182  	assert(IO_VALID(object));
1183  	assert(io_active(object));
1184  
1185  	/*
1186  	 *	If the space is the receiver/owner of the object,
1187  	 *	then we quietly consume the right and return
1188  	 *	the space's name for the object.  Otherwise
1189  	 *	we destroy the right and return MACH_PORT_NULL.
1190  	 */
1191  
1192  	switch (msgt_name) {
1193  	case MACH_MSG_TYPE_PORT_SEND: {
1194  		ipc_port_t port = ip_object_to_port(object);
1195  		ipc_port_t nsrequest = IP_NULL;
1196  		mach_port_mscount_t mscount;
1197  
1198  		if (port->ip_receiver == space) {
1199  			name = port->ip_receiver_name;
1200  		} else {
1201  			name = MACH_PORT_NULL;
1202  		}
1203  
1204  		assert(port->ip_srights > 0);
1205  		if (--port->ip_srights == 0 &&
1206  		    port->ip_nsrequest != IP_NULL) {
1207  			nsrequest = port->ip_nsrequest;
1208  			port->ip_nsrequest = IP_NULL;
1209  			mscount = port->ip_mscount;
1210  			ipc_port_clear_sync_rcv_thread_boost_locked(port);
1211  			/* port unlocked */
1212  			ipc_notify_no_senders(nsrequest, mscount);
1213  		} else {
1214  			ipc_port_clear_sync_rcv_thread_boost_locked(port);
1215  			/* port unlocked */
1216  		}
1217  
1218  		ip_release(port);
1219  		break;
1220  	}
1221  
1222  	case MACH_MSG_TYPE_PORT_SEND_ONCE: {
1223  		ipc_port_t port = ip_object_to_port(object);
1224  
1225  		assert(port->ip_sorights > 0);
1226  
1227  		if (port->ip_receiver == space) {
1228  			/* quietly consume the send-once right */
1229  
1230  			port->ip_sorights--;
1231  			name = port->ip_receiver_name;
1232  			ipc_port_clear_sync_rcv_thread_boost_locked(port);
1233  			/* port unlocked */
1234  			ip_release(port);
1235  		} else {
1236  			/*
1237  			 *	A very bizarre case.  The message
1238  			 *	was received, but before this copyout
1239  			 *	happened the space lost receive rights.
1240  			 *	We can't quietly consume the soright
1241  			 *	out from underneath some other task,
1242  			 *	so generate a send-once notification.
1243  			 */
1244  
1245  			ip_unlock(port);
1246  
1247  			ipc_notify_send_once(port);
1248  			name = MACH_PORT_NULL;
1249  		}
1250  
1251  		break;
1252  	}
1253  
1254  	default:
1255  		panic("ipc_object_copyout_dest: strange rights");
1256  		name = MACH_PORT_DEAD;
1257  	}
1258  
1259  	*namep = name;
1260  }
1261  
1262  /*
1263   *	Routine:        io_lock
1264   *	Purpose:
1265   *		Validate, then acquire a lock on an ipc object
1266   */
1267  
1268  void
1269  io_lock(ipc_object_t io)
1270  {
1271  	ipc_object_validate(io);
1272  	lck_spin_lock_grp(&(io)->io_lock_data, &ipc_lck_grp);
1273  }
1274  
1275  /*
1276   *	Routine:	io_lock_try
1277   *	Purpose:
1278   *		Validate, then try to acquire a lock on an object,
1279   *		fail if there is an existing busy lock
1280   */
1281  
1282  boolean_t
1283  io_lock_try(ipc_object_t io)
1284  {
1285  	ipc_object_validate(io);
1286  	return lck_spin_try_lock_grp(&(io)->io_lock_data, &ipc_lck_grp);
1287  }
1288  
1289  /*
1290   *	Check whether the object is a port if so, free it.  But
1291   *	keep track of that fact.
1292   */
1293  void
1294  io_free(
1295  	unsigned int    otype,
1296  	ipc_object_t    object)
1297  {
1298  	if (otype == IOT_PORT) {
1299  		ipc_port_finalize(ip_object_to_port(object));
1300  	}
1301  	io_lock_destroy(object);
1302  	zfree(ipc_object_zones[otype], object);
1303  }