/ duct-tape / xnu / osfmk / kern / ipc_kobject.c
ipc_kobject.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 SPARTA, Inc.
  62   */
  63  /*
  64   */
  65  /*
  66   *	File:	kern/ipc_kobject.c
  67   *	Author:	Rich Draves
  68   *	Date:	1989
  69   *
  70   *	Functions for letting a port represent a kernel object.
  71   */
  72  
  73  #include <mach_debug.h>
  74  #include <mach_ipc_test.h>
  75  #include <mach/mig.h>
  76  #include <mach/port.h>
  77  #include <mach/kern_return.h>
  78  #include <mach/message.h>
  79  #include <mach/mig_errors.h>
  80  #include <mach/notify.h>
  81  #include <mach/ndr.h>
  82  #include <mach/vm_param.h>
  83  
  84  #include <mach/mach_vm_server.h>
  85  #include <mach/mach_port_server.h>
  86  #include <mach/mach_host_server.h>
  87  #include <mach/host_priv_server.h>
  88  #include <mach/host_security_server.h>
  89  #include <mach/clock_server.h>
  90  #include <mach/clock_priv_server.h>
  91  #include <mach/lock_set_server.h>
  92  #include <mach/memory_entry_server.h>
  93  #include <mach/memory_object_control_server.h>
  94  #include <mach/memory_object_default_server.h>
  95  #include <mach/processor_server.h>
  96  #include <mach/processor_set_server.h>
  97  #include <mach/task_server.h>
  98  #include <mach/mach_voucher_server.h>
  99  #include <mach/mach_voucher_attr_control_server.h>
 100  #ifdef VM32_SUPPORT
 101  #include <mach/vm32_map_server.h>
 102  #endif
 103  #include <mach/thread_act_server.h>
 104  #include <mach/restartable_server.h>
 105  
 106  #include <mach/exc_server.h>
 107  #include <mach/mach_exc_server.h>
 108  #include <mach/mach_eventlink_server.h>
 109  
 110  #include <device/device_types.h>
 111  #include <device/device_server.h>
 112  
 113  #if     CONFIG_USER_NOTIFICATION
 114  #include <UserNotification/UNDReplyServer.h>
 115  #endif
 116  
 117  #if     CONFIG_ARCADE
 118  #include <mach/arcade_register_server.h>
 119  #endif
 120  
 121  #if     CONFIG_AUDIT
 122  #include <kern/audit_sessionport.h>
 123  #endif
 124  
 125  #if     MACH_MACHINE_ROUTINES
 126  #include <machine/machine_routines.h>
 127  #endif  /* MACH_MACHINE_ROUTINES */
 128  #if     XK_PROXY
 129  #include <uk_xkern/xk_uproxy_server.h>
 130  #endif  /* XK_PROXY */
 131  
 132  #include <kern/counter.h>
 133  #include <kern/ipc_tt.h>
 134  #include <kern/ipc_mig.h>
 135  #include <kern/ipc_misc.h>
 136  #include <kern/ipc_kobject.h>
 137  #include <kern/host_notify.h>
 138  #include <kern/mk_timer.h>
 139  #include <kern/misc_protos.h>
 140  
 141  #if CONFIG_ARCADE
 142  #include <kern/arcade.h>
 143  #endif /* CONFIG_ARCADE */
 144  
 145  #include <ipc/ipc_kmsg.h>
 146  #include <ipc/ipc_port.h>
 147  #include <ipc/ipc_voucher.h>
 148  #include <kern/sync_sema.h>
 149  #include <kern/work_interval.h>
 150  #include <kern/suid_cred.h>
 151  #include <kern/task_ident.h>
 152  
 153  #if HYPERVISOR
 154  #include <kern/hv_support.h>
 155  #endif
 156  
 157  #include <vm/vm_protos.h>
 158  
 159  #include <security/mac_mach_internal.h>
 160  
 161  extern char *proc_name_address(void *p);
 162  struct proc;
 163  extern int proc_pid(struct proc *p);
 164  
 165  /*
 166   *	Routine:	ipc_kobject_notify
 167   *	Purpose:
 168   *		Deliver notifications to kobjects that care about them.
 169   */
 170  boolean_t
 171  ipc_kobject_notify(
 172  	mach_msg_header_t *request_header,
 173  	mach_msg_header_t *reply_header);
 174  
 175  typedef struct {
 176  	mach_msg_id_t num;
 177  	mig_routine_t routine;
 178  	int size;
 179  	int kobjidx;
 180  } mig_hash_t;
 181  
 182  #define MAX_MIG_ENTRIES 1031
 183  #define MIG_HASH(x) (x)
 184  
 185  #define KOBJ_IDX_NOT_SET (-1)
 186  
 187  #ifndef max
 188  #define max(a, b)        (((a) > (b)) ? (a) : (b))
 189  #endif /* max */
 190  
 191  static SECURITY_READ_ONLY_LATE(mig_hash_t) mig_buckets[MAX_MIG_ENTRIES];
 192  static SECURITY_READ_ONLY_LATE(int) mig_table_max_displ;
 193  SECURITY_READ_ONLY_LATE(int) mach_kobj_count; /* count of total number of kobjects */
 194  
 195  static ZONE_DECLARE(ipc_kobject_label_zone, "ipc kobject labels",
 196      sizeof(struct ipc_kobject_label), ZC_NONE);
 197  
 198  __startup_data
 199  static const struct mig_subsystem *mig_e[] = {
 200  	(const struct mig_subsystem *)&mach_vm_subsystem,
 201  	(const struct mig_subsystem *)&mach_port_subsystem,
 202  	(const struct mig_subsystem *)&mach_host_subsystem,
 203  	(const struct mig_subsystem *)&host_priv_subsystem,
 204  	(const struct mig_subsystem *)&host_security_subsystem,
 205  	(const struct mig_subsystem *)&clock_subsystem,
 206  	(const struct mig_subsystem *)&clock_priv_subsystem,
 207  	(const struct mig_subsystem *)&processor_subsystem,
 208  	(const struct mig_subsystem *)&processor_set_subsystem,
 209  	(const struct mig_subsystem *)&is_iokit_subsystem,
 210  	(const struct mig_subsystem *)&lock_set_subsystem,
 211  	(const struct mig_subsystem *)&task_subsystem,
 212  	(const struct mig_subsystem *)&thread_act_subsystem,
 213  #ifdef VM32_SUPPORT
 214  	(const struct mig_subsystem *)&vm32_map_subsystem,
 215  #endif
 216  #if CONFIG_USER_NOTIFICATION
 217  	(const struct mig_subsystem *)&UNDReply_subsystem,
 218  #endif
 219  	(const struct mig_subsystem *)&mach_voucher_subsystem,
 220  	(const struct mig_subsystem *)&mach_voucher_attr_control_subsystem,
 221  	(const struct mig_subsystem *)&memory_entry_subsystem,
 222  	(const struct mig_subsystem *)&task_restartable_subsystem,
 223  
 224  #if     XK_PROXY
 225  	(const struct mig_subsystem *)&do_uproxy_xk_uproxy_subsystem,
 226  #endif /* XK_PROXY */
 227  #if     MACH_MACHINE_ROUTINES
 228  	(const struct mig_subsystem *)&MACHINE_SUBSYSTEM,
 229  #endif  /* MACH_MACHINE_ROUTINES */
 230  #if     MCMSG && iPSC860
 231  	(const struct mig_subsystem *)&mcmsg_info_subsystem,
 232  #endif  /* MCMSG && iPSC860 */
 233  	(const struct mig_subsystem *)&catch_exc_subsystem,
 234  	(const struct mig_subsystem *)&catch_mach_exc_subsystem,
 235  #if CONFIG_ARCADE
 236  	(const struct mig_subsystem *)&arcade_register_subsystem,
 237  #endif
 238  	(const struct mig_subsystem *)&mach_eventlink_subsystem,
 239  };
 240  
 241  #ifdef __DARLING__
 242  void
 243  #else
 244  static void
 245  #endif // ___DARLING__
 246  mig_init(void)
 247  {
 248  #ifdef __DARLING__
 249  	ipc_kobject_label_zone = zone_create("ipc kobject labels", sizeof(struct ipc_kobject_label), ZC_NONE);
 250  #endif // __DARLING__
 251  
 252  	unsigned int i, n = sizeof(mig_e) / sizeof(const struct mig_subsystem *);
 253  	int howmany;
 254  	mach_msg_id_t j, pos, nentry, range;
 255  
 256  	for (i = 0; i < n; i++) {
 257  		range = mig_e[i]->end - mig_e[i]->start;
 258  		if (!mig_e[i]->start || range < 0) {
 259  			panic("the msgh_ids in mig_e[] aren't valid!");
 260  		}
 261  
 262  		for (j = 0; j < range; j++) {
 263  			if (mig_e[i]->routine[j].stub_routine) {
 264  				/* Only put real entries in the table */
 265  				nentry = j + mig_e[i]->start;
 266  				for (pos = MIG_HASH(nentry) % MAX_MIG_ENTRIES, howmany = 1;
 267  				    mig_buckets[pos].num;
 268  				    pos++, pos = pos % MAX_MIG_ENTRIES, howmany++) {
 269  					if (mig_buckets[pos].num == nentry) {
 270  						printf("message id = %d\n", nentry);
 271  						panic("multiple entries with the same msgh_id");
 272  					}
 273  					if (howmany == MAX_MIG_ENTRIES) {
 274  						panic("the mig dispatch table is too small");
 275  					}
 276  				}
 277  
 278  				mig_buckets[pos].num = nentry;
 279  				mig_buckets[pos].routine = mig_e[i]->routine[j].stub_routine;
 280  				if (mig_e[i]->routine[j].max_reply_msg) {
 281  					mig_buckets[pos].size = mig_e[i]->routine[j].max_reply_msg;
 282  				} else {
 283  					mig_buckets[pos].size = mig_e[i]->maxsize;
 284  				}
 285  				mig_buckets[pos].kobjidx = KOBJ_IDX_NOT_SET;
 286  
 287  				mig_table_max_displ = max(howmany, mig_table_max_displ);
 288  				mach_kobj_count++;
 289  			}
 290  		}
 291  	}
 292  #ifdef __DARLING__
 293  	#include <darlingserver/duct-tape/log.h>
 294  	dtape_log_debug("mig_table_max_displ = %d mach_kobj_count = %d\n",
 295  	    mig_table_max_displ, mach_kobj_count);
 296  #else
 297  	printf("mig_table_max_displ = %d mach_kobj_count = %d\n",
 298  	    mig_table_max_displ, mach_kobj_count);
 299  #endif
 300  }
 301  STARTUP(MACH_IPC, STARTUP_RANK_FIRST, mig_init);
 302  
 303  /*
 304   * Do a hash table lookup for given msgh_id. Return 0
 305   * if not found.
 306   */
 307  static mig_hash_t *
 308  find_mig_hash_entry(int msgh_id)
 309  {
 310  	unsigned int i = (unsigned int)MIG_HASH(msgh_id);
 311  	int max_iter = mig_table_max_displ;
 312  	mig_hash_t *ptr;
 313  
 314  	do {
 315  		ptr = &mig_buckets[i++ % MAX_MIG_ENTRIES];
 316  	} while (msgh_id != ptr->num && ptr->num && --max_iter);
 317  
 318  	if (!ptr->routine || msgh_id != ptr->num) {
 319  		ptr = (mig_hash_t *)0;
 320  	}
 321  
 322  	return ptr;
 323  }
 324  
 325  /*
 326   *      Routine:	ipc_kobject_set_kobjidx
 327   *      Purpose:
 328   *              Set the index for the kobject filter
 329   *              mask for a given message ID.
 330   */
 331  kern_return_t
 332  ipc_kobject_set_kobjidx(
 333  	int       msgh_id,
 334  	int       index)
 335  {
 336  	mig_hash_t *ptr = find_mig_hash_entry(msgh_id);
 337  
 338  	if (ptr == (mig_hash_t *)0) {
 339  		return KERN_INVALID_ARGUMENT;
 340  	}
 341  
 342  	assert(index < mach_kobj_count);
 343  	ptr->kobjidx = index;
 344  
 345  	return KERN_SUCCESS;
 346  }
 347  
 348  /*
 349   *	Routine:	ipc_kobject_server
 350   *	Purpose:
 351   *		Handle a message sent to the kernel.
 352   *		Generates a reply message.
 353   *		Version for Untyped IPC.
 354   *	Conditions:
 355   *		Nothing locked.
 356   */
 357  
 358  ipc_kmsg_t
 359  ipc_kobject_server(
 360  	ipc_kmsg_t      request,
 361  	mach_msg_option_t __unused option)
 362  {
 363  	mach_msg_size_t reply_size;
 364  	ipc_kmsg_t reply;
 365  	kern_return_t kr;
 366  	ipc_port_t  replyp = IPC_PORT_NULL;
 367  	mach_msg_max_trailer_t *trailer;
 368  	mig_hash_t *ptr;
 369  	task_t task = TASK_NULL;
 370  	uint32_t exec_token;
 371  	boolean_t exec_token_changed = FALSE;
 372  	int request_msgh_id = request->ikm_header->msgh_id;
 373  	natural_t ikot;
 374  	ipc_port_t port;
 375  
 376  	reply = NULL;
 377  	port = request->ikm_header->msgh_remote_port;
 378  	if (IP_VALID(port)) {
 379  		ikot = ip_kotype(port);
 380  	} else {
 381  		ikot = IKOT_UNKNOWN;
 382  	}
 383  	if (ikot == IKOT_UEXT_OBJECT) {
 384  		kr = uext_server(request, &reply);
 385  		if ((MIG_NO_REPLY == kr) || (KERN_SUCCESS == kr)) {
 386  			ipc_kmsg_trace_send(request, option);
 387  			goto msgdone;
 388  		}
 389  	}
 390  
 391  	/* Find corresponding mig_hash entry, if any */
 392  	ptr = find_mig_hash_entry(request_msgh_id);
 393  
 394  	/* Get the reply_size. */
 395  	if (ptr == (mig_hash_t *)0) {
 396  		reply_size = sizeof(mig_reply_error_t);
 397  	} else {
 398  		reply_size = ptr->size;
 399  	}
 400  
 401  	/* round up for trailer size */
 402  	reply_size += MAX_TRAILER_SIZE;
 403  	reply = ipc_kmsg_alloc(reply_size);
 404  
 405  	if (reply == IKM_NULL) {
 406  		printf("ipc_kobject_server: dropping request\n");
 407  		ipc_kmsg_trace_send(request, option);
 408  		ipc_kmsg_destroy(request);
 409  		return IKM_NULL;
 410  	}
 411  
 412  	/*
 413  	 * Initialize reply message.
 414  	 */
 415  	{
 416  #define InP     ((mach_msg_header_t *) request->ikm_header)
 417  #define OutP    ((mig_reply_error_t *) reply->ikm_header)
 418  
 419  		/*
 420  		 * MIG should really assure no data leakage -
 421  		 * but until it does, pessimistically zero the
 422  		 * whole reply buffer.
 423  		 */
 424  		bzero((void *)OutP, reply_size);
 425  
 426  		OutP->NDR = NDR_record;
 427  		OutP->Head.msgh_size = sizeof(mig_reply_error_t);
 428  
 429  		OutP->Head.msgh_bits =
 430  		    MACH_MSGH_BITS_SET(MACH_MSGH_BITS_LOCAL(InP->msgh_bits), 0, 0, 0);
 431  		OutP->Head.msgh_remote_port = InP->msgh_local_port;
 432  		OutP->Head.msgh_local_port = MACH_PORT_NULL;
 433  		OutP->Head.msgh_voucher_port = MACH_PORT_NULL;
 434  		OutP->Head.msgh_id = InP->msgh_id + 100;
 435  
 436  #undef  InP
 437  #undef  OutP
 438  	}
 439  
 440  	/*
 441  	 * Find the routine to call, and call it
 442  	 * to perform the kernel function
 443  	 */
 444  	ipc_kmsg_trace_send(request, option);
 445  	{
 446  		if (ptr) {
 447  			/*
 448  			 * Check if the port is a task port, if its a task port then
 449  			 * snapshot the task exec token before the mig routine call.
 450  			 */
 451  			if (ikot == IKOT_TASK_CONTROL) {
 452  				task = convert_port_to_task_with_exec_token(port, &exec_token, TRUE);
 453  			}
 454  
 455  #if CONFIG_MACF
 456  			int idx = ptr->kobjidx;
 457  			task_t curtask = current_task();
 458  			uint8_t *filter_mask = curtask->mach_kobj_filter_mask;
 459  
 460  			/* Check kobject mig filter mask, if exists. */
 461  			if (__improbable(filter_mask != NULL && idx != KOBJ_IDX_NOT_SET &&
 462  			    !bitstr_test(filter_mask, idx))) {
 463  				/* Not in filter mask, evaluate policy. */
 464  				if (mac_task_kobj_msg_evaluate != NULL) {
 465  					kr = mac_task_kobj_msg_evaluate(get_bsdtask_info(curtask),
 466  					    request_msgh_id, idx);
 467  					if (kr != KERN_SUCCESS) {
 468  						((mig_reply_error_t *) reply->ikm_header)->RetCode = kr;
 469  						goto skip_kobjcall;
 470  					}
 471  				}
 472  			}
 473  #endif /* CONFIG_MACF */
 474  
 475  			(*ptr->routine)(request->ikm_header, reply->ikm_header);
 476  
 477  #if CONFIG_MACF
 478  skip_kobjcall:
 479  #endif
 480  
 481  			/* Check if the exec token changed during the mig routine */
 482  			if (task != TASK_NULL) {
 483  				if (exec_token != task->exec_token) {
 484  					exec_token_changed = TRUE;
 485  				}
 486  				task_deallocate(task);
 487  			}
 488  
 489  			kernel_task->messages_received++;
 490  		} else {
 491  			if (!ipc_kobject_notify(request->ikm_header, reply->ikm_header)) {
 492  #if DEVELOPMENT || DEBUG
 493  				printf("ipc_kobject_server: bogus kernel message, id=%d\n",
 494  				    request->ikm_header->msgh_id);
 495  #endif  /* DEVELOPMENT || DEBUG */
 496  				_MIG_MSGID_INVALID(request->ikm_header->msgh_id);
 497  
 498  				((mig_reply_error_t *) reply->ikm_header)->RetCode
 499  				        = MIG_BAD_ID;
 500  			} else {
 501  				kernel_task->messages_received++;
 502  			}
 503  		}
 504  		kernel_task->messages_sent++;
 505  	}
 506  
 507  	if (!(reply->ikm_header->msgh_bits & MACH_MSGH_BITS_COMPLEX) &&
 508  	    ((mig_reply_error_t *) reply->ikm_header)->RetCode != KERN_SUCCESS) {
 509  		kr = ((mig_reply_error_t *) reply->ikm_header)->RetCode;
 510  	} else {
 511  		kr = KERN_SUCCESS;
 512  	}
 513  
 514  msgdone:
 515  	/*
 516  	 *	Destroy destination. The following code differs from
 517  	 *	ipc_object_destroy in that we release the send-once
 518  	 *	right instead of generating a send-once notification
 519  	 *	(which would bring us here again, creating a loop).
 520  	 *	It also differs in that we only expect send or
 521  	 *	send-once rights, never receive rights.
 522  	 *
 523  	 *	We set msgh_remote_port to IP_NULL so that the kmsg
 524  	 *	destroy routines don't try to destroy the port twice.
 525  	 */
 526  	switch (MACH_MSGH_BITS_REMOTE(request->ikm_header->msgh_bits)) {
 527  	case MACH_MSG_TYPE_PORT_SEND:
 528  		ipc_port_release_send(request->ikm_header->msgh_remote_port);
 529  		request->ikm_header->msgh_remote_port = IP_NULL;
 530  		break;
 531  
 532  	case MACH_MSG_TYPE_PORT_SEND_ONCE:
 533  		ipc_port_release_sonce(request->ikm_header->msgh_remote_port);
 534  		request->ikm_header->msgh_remote_port = IP_NULL;
 535  		break;
 536  
 537  	default:
 538  		panic("ipc_kobject_server: strange destination rights");
 539  	}
 540  
 541  	/*
 542  	 *	Destroy voucher.  The kernel MIG servers never take ownership
 543  	 *	of vouchers sent in messages.  Swallow any such rights here.
 544  	 */
 545  	if (IP_VALID(request->ikm_voucher)) {
 546  		assert(MACH_MSG_TYPE_PORT_SEND ==
 547  		    MACH_MSGH_BITS_VOUCHER(request->ikm_header->msgh_bits));
 548  		ipc_port_release_send(request->ikm_voucher);
 549  		request->ikm_voucher = IP_NULL;
 550  	}
 551  
 552  	if ((kr == KERN_SUCCESS) || (kr == MIG_NO_REPLY)) {
 553  		/*
 554  		 *	The server function is responsible for the contents
 555  		 *	of the message.  The reply port right is moved
 556  		 *	to the reply message, and we have deallocated
 557  		 *	the destination port right, so we just need
 558  		 *	to free the kmsg.
 559  		 */
 560  		ipc_kmsg_free(request);
 561  	} else {
 562  		/*
 563  		 *	The message contents of the request are intact.
 564  		 *	Destroy everthing except the reply port right,
 565  		 *	which is needed in the reply message.
 566  		 */
 567  		request->ikm_header->msgh_local_port = MACH_PORT_NULL;
 568  		ipc_kmsg_destroy(request);
 569  	}
 570  
 571  	if (kr == MIG_NO_REPLY) {
 572  		/*
 573  		 *	The server function will send a reply message
 574  		 *	using the reply port right, which it has saved.
 575  		 */
 576  
 577  		if (reply) {
 578  			ipc_kmsg_free(reply);
 579  		}
 580  		return IKM_NULL;
 581  	}
 582  
 583  	if (reply) {
 584  		replyp = reply->ikm_header->msgh_remote_port;
 585  	}
 586  
 587  	if (!IP_VALID(replyp)) {
 588  		/*
 589  		 *	Can't queue the reply message if the destination
 590  		 *	(the reply port) isn't valid.
 591  		 */
 592  
 593  		ipc_kmsg_destroy(reply);
 594  
 595  		return IKM_NULL;
 596  	} else if (replyp->ip_receiver == ipc_space_kernel) {
 597  		/*
 598  		 * Don't send replies to kobject kernel ports
 599  		 */
 600  #if DEVELOPMENT || DEBUG
 601  		printf("%s: refusing to send reply to kobject %d port (id:%d)\n",
 602  		    __func__, ip_kotype(replyp), request_msgh_id);
 603  #endif  /* DEVELOPMENT || DEBUG */
 604  		ipc_kmsg_destroy(reply);
 605  		return IKM_NULL;
 606  	}
 607  
 608  	/* Fail the MIG call if the task exec token changed during the call */
 609  	if (kr == KERN_SUCCESS && exec_token_changed) {
 610  		/*
 611  		 *	Create a new reply msg with error and destroy the old reply msg.
 612  		 */
 613  		ipc_kmsg_t new_reply = ipc_kmsg_alloc(reply_size);
 614  
 615  		if (new_reply == IKM_NULL) {
 616  			printf("ipc_kobject_server: dropping request\n");
 617  			ipc_kmsg_destroy(reply);
 618  			return IKM_NULL;
 619  		}
 620  		/*
 621  		 *	Initialize the new reply message.
 622  		 */
 623  		{
 624  #define OutP_new        ((mig_reply_error_t *) new_reply->ikm_header)
 625  #define OutP_old        ((mig_reply_error_t *) reply->ikm_header)
 626  
 627  			bzero((void *)OutP_new, reply_size);
 628  
 629  			OutP_new->NDR = OutP_old->NDR;
 630  			OutP_new->Head.msgh_size = sizeof(mig_reply_error_t);
 631  			OutP_new->Head.msgh_bits = OutP_old->Head.msgh_bits & ~MACH_MSGH_BITS_COMPLEX;
 632  			OutP_new->Head.msgh_remote_port = OutP_old->Head.msgh_remote_port;
 633  			OutP_new->Head.msgh_local_port = MACH_PORT_NULL;
 634  			OutP_new->Head.msgh_voucher_port = MACH_PORT_NULL;
 635  			OutP_new->Head.msgh_id = OutP_old->Head.msgh_id;
 636  
 637  			/* Set the error as KERN_INVALID_TASK */
 638  			OutP_new->RetCode = KERN_INVALID_TASK;
 639  
 640  #undef  OutP_new
 641  #undef  OutP_old
 642  		}
 643  
 644  		/*
 645  		 *	Destroy everything in reply except the reply port right,
 646  		 *	which is needed in the new reply message.
 647  		 */
 648  		reply->ikm_header->msgh_remote_port = MACH_PORT_NULL;
 649  		ipc_kmsg_destroy(reply);
 650  
 651  		reply = new_reply;
 652  	}
 653  
 654  	trailer = (mach_msg_max_trailer_t *)
 655  	    ((vm_offset_t)reply->ikm_header + (int)reply->ikm_header->msgh_size);
 656  	bzero(trailer, sizeof(*trailer));
 657  	trailer->msgh_sender = KERNEL_SECURITY_TOKEN;
 658  	trailer->msgh_audit = KERNEL_AUDIT_TOKEN;
 659  	trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
 660  	trailer->msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE;
 661  
 662  	return reply;
 663  }
 664  
 665  /*
 666   *	Routine:	ipc_kobject_set
 667   *	Purpose:
 668   *		Make a port represent a kernel object of the given type.
 669   *		The caller is responsible for handling refs for the
 670   *		kernel object, if necessary.
 671   *	Conditions:
 672   *		Nothing locked.  The port must be active if setting
 673   *		a kobject linkage.  Clearing a linkage is OK on an
 674   *		inactive port.
 675   */
 676  void
 677  ipc_kobject_set(
 678  	ipc_port_t                      port,
 679  	ipc_kobject_t           kobject,
 680  	ipc_kobject_type_t      type)
 681  {
 682  	ip_lock(port);
 683  	ipc_kobject_set_atomically(port, kobject, type);
 684  	ip_unlock(port);
 685  }
 686  
 687  void
 688  ipc_kobject_set_atomically(
 689  	ipc_port_t                      port,
 690  	ipc_kobject_t           kobject,
 691  	ipc_kobject_type_t      type)
 692  {
 693  	assert(type == IKOT_NONE || ip_active(port));
 694  #if     MACH_ASSERT
 695  	port->ip_spares[2] = (port->ip_object.io_bits & IO_BITS_KOTYPE);
 696  #endif  /* MACH_ASSERT */
 697  	port->ip_object.io_bits = (port->ip_object.io_bits & ~IO_BITS_KOTYPE) | type;
 698  	if (ip_is_kolabeled(port)) {
 699  		ipc_kobject_label_t labelp = port->ip_kolabel;
 700  		labelp->ikol_kobject = kobject;
 701  	} else {
 702  		port->ip_kobject = kobject;
 703  	}
 704  	if (type != IKOT_NONE) {
 705  		/* Once set, this bit can never be unset */
 706  		port->ip_object.io_bits |= IO_BITS_KOBJECT;
 707  	}
 708  }
 709  
 710  /*
 711   *	Routine:	ipc_kobject_init_port
 712   *	Purpose:
 713   *		Initialize a kobject port with the given types and options.
 714   *
 715   *		This function never fails.
 716   */
 717  static inline void
 718  ipc_kobject_init_port(
 719  	ipc_port_t port,
 720  	ipc_kobject_t kobject,
 721  	ipc_kobject_type_t type,
 722  	ipc_kobject_alloc_options_t options)
 723  {
 724  	ipc_kobject_set_atomically(port, kobject, type);
 725  
 726  	if (options & IPC_KOBJECT_ALLOC_MAKE_SEND) {
 727  		ipc_port_make_send_locked(port);
 728  	}
 729  	if (options & IPC_KOBJECT_ALLOC_NSREQUEST) {
 730  		ipc_port_make_sonce_locked(port);
 731  		port->ip_nsrequest = port;
 732  	}
 733  	if (options & IPC_KOBJECT_ALLOC_NO_GRANT) {
 734  		port->ip_no_grant = 1;
 735  	}
 736  	if (options & IPC_KOBJECT_ALLOC_IMMOVABLE_SEND) {
 737  		port->ip_immovable_send = 1;
 738  	}
 739  	if (options & IPC_KOBJECT_ALLOC_PINNED) {
 740  		port->ip_pinned = 1;
 741  	}
 742  }
 743  
 744  /*
 745   *	Routine:	ipc_kobject_alloc_port
 746   *	Purpose:
 747   *		Allocate a kobject port in the kernel space of the specified type.
 748   *
 749   *		This function never fails.
 750   *
 751   *	Conditions:
 752   *		No locks held (memory is allocated)
 753   */
 754  ipc_port_t
 755  ipc_kobject_alloc_port(
 756  	ipc_kobject_t           kobject,
 757  	ipc_kobject_type_t      type,
 758  	ipc_kobject_alloc_options_t     options)
 759  {
 760  	ipc_port_t port = ipc_port_alloc_kernel();
 761  
 762  	if (port == IP_NULL) {
 763  		panic("ipc_kobject_alloc_port(): failed to allocate port");
 764  	}
 765  
 766  	ipc_kobject_init_port(port, kobject, type, options);
 767  	return port;
 768  }
 769  
 770  /*
 771   *	Routine:	ipc_kobject_alloc_labeled_port
 772   *	Purpose:
 773   *		Allocate a kobject port and associated mandatory access label
 774   *		in the kernel space of the specified type.
 775   *
 776   *		This function never fails.
 777   *
 778   *	Conditions:
 779   *		No locks held (memory is allocated)
 780   */
 781  
 782  ipc_port_t
 783  ipc_kobject_alloc_labeled_port(
 784  	ipc_kobject_t           kobject,
 785  	ipc_kobject_type_t      type,
 786  	ipc_label_t             label,
 787  	ipc_kobject_alloc_options_t     options)
 788  {
 789  	ipc_port_t port;
 790  	ipc_kobject_label_t labelp;
 791  
 792  	port = ipc_port_alloc_kernel();
 793  	if (port == IP_NULL) {
 794  		panic("ipc_kobject_alloc_port(): failed to allocate port");
 795  	}
 796  
 797  	labelp = (ipc_kobject_label_t)zalloc(ipc_kobject_label_zone);
 798  	if (labelp == NULL) {
 799  		panic("ipc_kobject_alloc_labeled_port(): failed to allocate label");
 800  	}
 801  	labelp->ikol_label = label;
 802  	port->ip_kolabel = labelp;
 803  	port->ip_object.io_bits |= IO_BITS_KOLABEL;
 804  
 805  	ipc_kobject_init_port(port, kobject, type, options);
 806  	return port;
 807  }
 808  
 809  static void
 810  ipc_kobject_subst_once_notify(mach_msg_header_t *msg)
 811  {
 812  	mach_no_senders_notification_t *notification = (void *)msg;
 813  	ipc_port_t port = notification->not_header.msgh_remote_port;
 814  
 815  	require_ip_active(port);
 816  	assert(IKOT_PORT_SUBST_ONCE == ip_kotype(port));
 817  
 818  	ip_release((ipc_port_t)ip_get_kobject(port));
 819  	ipc_port_dealloc_kernel(port);
 820  }
 821  
 822  /*
 823   *	Routine:	ipc_kobject_alloc_subst_once
 824   *	Purpose:
 825   *		Make a port that will be substituted by the kolabel
 826   *		rules once, preventing the next substitution (of its target)
 827   *		to happen if any.
 828   *
 829   *	Returns:
 830   *		A port with a send right, that will substitute to its "kobject".
 831   *
 832   *	Conditions:
 833   *		No locks held (memory is allocated)
 834   *		`target` has a refcount that this function consumes
 835   */
 836  ipc_port_t
 837  ipc_kobject_alloc_subst_once(
 838  	ipc_port_t                  target)
 839  {
 840  	return ipc_kobject_alloc_labeled_port(target,
 841  	           IKOT_PORT_SUBST_ONCE, IPC_LABEL_SUBST_ONCE,
 842  	           IPC_KOBJECT_ALLOC_MAKE_SEND | IPC_KOBJECT_ALLOC_NSREQUEST);
 843  }
 844  
 845  /*
 846   *	Routine:	ipc_kobject_make_send_lazy_alloc_port
 847   *	Purpose:
 848   *		Make a send once for a kobject port.
 849   *
 850   *		A location owning this port is passed in port_store.
 851   *		If no port exists, a port is made lazily.
 852   *
 853   *		A send right is made for the port, and if this is the first one
 854   *		(possibly not for the first time), then the no-more-senders
 855   *		notification is rearmed.
 856   *
 857   *		When a notification is armed, the kobject must donate
 858   *		one of its references to the port. It is expected
 859   *		the no-more-senders notification will consume this reference.
 860   *
 861   *	Returns:
 862   *		TRUE if a notification was armed
 863   *		FALSE else
 864   *
 865   *	Conditions:
 866   *		Nothing is locked, memory can be allocated.
 867   *		The caller must be able to donate a kobject reference to the port.
 868   */
 869  boolean_t
 870  ipc_kobject_make_send_lazy_alloc_port(
 871  	ipc_port_t              *port_store,
 872  	ipc_kobject_t           kobject,
 873  	ipc_kobject_type_t      type,
 874  	ipc_kobject_alloc_options_t alloc_opts,
 875  	boolean_t               __ptrauth_only should_ptrauth,
 876  	uint64_t                __ptrauth_only ptrauth_discriminator)
 877  {
 878  	ipc_port_t port, previous, __ptrauth_only port_addr;
 879  	boolean_t rc = FALSE;
 880  
 881  	port = os_atomic_load(port_store, dependency);
 882  
 883  #if __has_feature(ptrauth_calls)
 884  	/* If we're on a ptrauth system and this port is signed, authenticate and strip the pointer */
 885  	if (should_ptrauth && IP_VALID(port)) {
 886  		port = ptrauth_auth_data(port,
 887  		    ptrauth_key_process_independent_data,
 888  		    ptrauth_blend_discriminator(port_store, ptrauth_discriminator));
 889  	}
 890  #endif // __has_feature(ptrauth_calls)
 891  
 892  	if (!IP_VALID(port)) {
 893  		port = ipc_kobject_alloc_port(kobject, type,
 894  		    IPC_KOBJECT_ALLOC_MAKE_SEND | IPC_KOBJECT_ALLOC_NSREQUEST | alloc_opts);
 895  
 896  #if __has_feature(ptrauth_calls)
 897  		if (should_ptrauth) {
 898  			port_addr = ptrauth_sign_unauthenticated(port,
 899  			    ptrauth_key_process_independent_data,
 900  			    ptrauth_blend_discriminator(port_store, ptrauth_discriminator));
 901  		} else {
 902  			port_addr = port;
 903  		}
 904  #else
 905  		port_addr = port;
 906  #endif // __has_feature(ptrauth_calls)
 907  
 908  		if (os_atomic_cmpxchgv(port_store, IP_NULL, port_addr, &previous, release)) {
 909  			return TRUE;
 910  		}
 911  
 912  		// undo what ipc_kobject_alloc_port() did above
 913  		port->ip_nsrequest = IP_NULL;
 914  		port->ip_mscount = 0;
 915  		port->ip_sorights = 0;
 916  		port->ip_srights = 0;
 917  		ip_release(port);
 918  		ip_release(port);
 919  		ipc_port_dealloc_kernel(port);
 920  
 921  		port = previous;
 922  	}
 923  
 924  	ip_lock(port);
 925  	ipc_port_make_send_locked(port);
 926  	if (port->ip_srights == 1) {
 927  		ipc_port_make_sonce_locked(port);
 928  		assert(port->ip_nsrequest == IP_NULL);
 929  		port->ip_nsrequest = port;
 930  		rc = TRUE;
 931  	}
 932  	ip_unlock(port);
 933  
 934  	return rc;
 935  }
 936  
 937  /*
 938   *	Routine:	ipc_kobject_make_send_lazy_alloc_labeled_port
 939   *	Purpose:
 940   *		Make a send once for a kobject port.
 941   *
 942   *		A location owning this port is passed in port_store.
 943   *		If no port exists, a port is made lazily.
 944   *
 945   *		A send right is made for the port, and if this is the first one
 946   *		(possibly not for the first time), then the no-more-senders
 947   *		notification is rearmed.
 948   *
 949   *		When a notification is armed, the kobject must donate
 950   *		one of its references to the port. It is expected
 951   *		the no-more-senders notification will consume this reference.
 952   *
 953   *	Returns:
 954   *		TRUE if a notification was armed
 955   *		FALSE else
 956   *
 957   *	Conditions:
 958   *		Nothing is locked, memory can be allocated.
 959   *		The caller must be able to donate a kobject reference to the port.
 960   */
 961  boolean_t
 962  ipc_kobject_make_send_lazy_alloc_labeled_port(
 963  	ipc_port_t              *port_store,
 964  	ipc_kobject_t           kobject,
 965  	ipc_kobject_type_t      type,
 966  	ipc_label_t             label)
 967  {
 968  	ipc_port_t port, previous;
 969  	boolean_t rc = FALSE;
 970  
 971  	port = os_atomic_load(port_store, dependency);
 972  
 973  	if (!IP_VALID(port)) {
 974  		port = ipc_kobject_alloc_labeled_port(kobject, type, label,
 975  		    IPC_KOBJECT_ALLOC_MAKE_SEND | IPC_KOBJECT_ALLOC_NSREQUEST);
 976  		if (os_atomic_cmpxchgv(port_store, IP_NULL, port, &previous, release)) {
 977  			return TRUE;
 978  		}
 979  
 980  		// undo what ipc_kobject_alloc_port() did above
 981  		port->ip_nsrequest = IP_NULL;
 982  		port->ip_mscount = 0;
 983  		port->ip_sorights = 0;
 984  		port->ip_srights = 0;
 985  		ip_release(port);
 986  		ip_release(port);
 987  		zfree(ipc_kobject_label_zone, port->ip_kolabel);
 988  		port->ip_object.io_bits &= ~IO_BITS_KOLABEL;
 989  		port->ip_kolabel = NULL;
 990  		ipc_port_dealloc_kernel(port);
 991  
 992  		port = previous;
 993  		assert(ip_is_kolabeled(port));
 994  	}
 995  
 996  	ip_lock(port);
 997  	ipc_port_make_send_locked(port);
 998  	if (port->ip_srights == 1) {
 999  		ipc_port_make_sonce_locked(port);
1000  		assert(port->ip_nsrequest == IP_NULL);
1001  		port->ip_nsrequest = port;
1002  		rc = TRUE;
1003  	}
1004  	ip_unlock(port);
1005  
1006  	return rc;
1007  }
1008  
1009  
1010  /*
1011   *	Routine:	ipc_kobject_destroy
1012   *	Purpose:
1013   *		Release any kernel object resources associated
1014   *		with the port, which is being destroyed.
1015   *
1016   *		This path to free object resources should only be
1017   *      needed when resources are associated with a user's port.
1018   *      In the normal case, when the kernel is the receiver,
1019   *      the code calling ipc_port_dealloc_kernel should clean
1020   *      up the object resources.
1021   *
1022   *      Cleans up any kobject label that might be present.
1023   *	Conditions:
1024   *		The port is not locked, but it is dead.
1025   */
1026  
1027  void
1028  ipc_kobject_destroy(
1029  	ipc_port_t              port)
1030  {
1031  	switch (ip_kotype(port)) {
1032  	case IKOT_TIMER:
1033  		mk_timer_port_destroy(port);
1034  		break;
1035  
1036  	case IKOT_NAMED_ENTRY:
1037  		mach_destroy_memory_entry(port);
1038  		break;
1039  
1040  	case IKOT_HOST_NOTIFY:
1041  		host_notify_port_destroy(port);
1042  		break;
1043  
1044  	case IKOT_SUID_CRED:
1045  		suid_cred_destroy(port);
1046  		break;
1047  
1048  	default:
1049  		break;
1050  	}
1051  
1052  	if (ip_is_kolabeled(port)) {
1053  		ipc_kobject_label_t labelp = port->ip_kolabel;
1054  
1055  		assert(labelp != NULL);
1056  		assert(ip_is_kobject(port));
1057  		port->ip_kolabel = NULL;
1058  		port->ip_object.io_bits &= ~IO_BITS_KOLABEL;
1059  		zfree(ipc_kobject_label_zone, labelp);
1060  	}
1061  }
1062  
1063  /*
1064   *	Routine:	ipc_kobject_label_substitute_task
1065   *	Purpose:
1066   *		Substitute a task control port for its immovable
1067   *		equivalent when the receiver is that task.
1068   *	Conditions:
1069   *		Space is write locked and active.
1070   *		Port is locked and active.
1071   *	Returns:
1072   *		- IP_NULL port if no substitution is to be done
1073   *		- a valid port if a substitution needs to happen
1074   */
1075  static ipc_port_t
1076  ipc_kobject_label_substitute_task(
1077  	ipc_space_t             space,
1078  	ipc_port_t              port)
1079  {
1080  	ipc_port_t subst = IP_NULL;
1081  	task_t task = ipc_kobject_get(port);
1082  
1083  	if (task != TASK_NULL && task == space->is_task) {
1084  		if ((subst = port->ip_alt_port)) {
1085  			return subst;
1086  		}
1087  	}
1088  
1089  	return IP_NULL;
1090  }
1091  
1092  /*
1093   *	Routine:	ipc_kobject_label_substitute_thread
1094   *	Purpose:
1095   *		Substitute a thread control port for its immovable
1096   *		equivalent when it belongs to the receiver task.
1097   *	Conditions:
1098   *		Space is write locked and active.
1099   *		Port is locked and active.
1100   *	Returns:
1101   *		- IP_NULL port if no substitution is to be done
1102   *		- a valid port if a substitution needs to happen
1103   */
1104  static ipc_port_t
1105  ipc_kobject_label_substitute_thread(
1106  	ipc_space_t             space,
1107  	ipc_port_t              port)
1108  {
1109  	ipc_port_t subst = IP_NULL;
1110  	thread_t thread = ipc_kobject_get(port);
1111  
1112  	if (thread != THREAD_NULL && space->is_task == thread->task) {
1113  		if ((subst = port->ip_alt_port) != IP_NULL) {
1114  			return subst;
1115  		}
1116  	}
1117  
1118  	return IP_NULL;
1119  }
1120  
1121  /*
1122   *	Routine:	ipc_kobject_label_check
1123   *	Purpose:
1124   *		Check to see if the space is allowed to possess
1125   *		a right for the given port. In order to qualify,
1126   *		the space label must contain all the privileges
1127   *		listed in the port/kobject label.
1128   *
1129   *	Conditions:
1130   *		Space is write locked and active.
1131   *		Port is locked and active.
1132   *
1133   *	Returns:
1134   *		Whether the copyout is authorized.
1135   *
1136   *		If a port substitution is requested, the space is unlocked,
1137   *		the port is unlocked and its "right" consumed.
1138   *
1139   *		As of now, substituted ports only happen for send rights.
1140   */
1141  bool
1142  ipc_kobject_label_check(
1143  	ipc_space_t                     space,
1144  	ipc_port_t                      port,
1145  	mach_msg_type_name_t            msgt_name,
1146  	ipc_object_copyout_flags_t     *flags,
1147  	ipc_port_t                     *subst_portp)
1148  {
1149  	ipc_kobject_label_t labelp;
1150  	ipc_label_t label;
1151  
1152  	assert(is_active(space));
1153  	assert(ip_active(port));
1154  
1155  	*subst_portp = IP_NULL;
1156  
1157  	/* Unlabled ports/kobjects are always allowed */
1158  	if (!ip_is_kolabeled(port)) {
1159  		return true;
1160  	}
1161  
1162  	/* Never OK to copyout the receive right for a labeled kobject */
1163  	if (msgt_name == MACH_MSG_TYPE_PORT_RECEIVE) {
1164  		panic("ipc_kobject_label_check: attempted receive right "
1165  		    "copyout for labeled kobject");
1166  	}
1167  
1168  	labelp = port->ip_kolabel;
1169  	label = labelp->ikol_label;
1170  
1171  	if ((*flags & IPC_OBJECT_COPYOUT_FLAGS_NO_LABEL_CHECK) == 0 &&
1172  	    (label & IPC_LABEL_SUBST_MASK)) {
1173  		ipc_port_t subst = IP_NULL;
1174  
1175  		if (msgt_name != MACH_MSG_TYPE_PORT_SEND) {
1176  			return false;
1177  		}
1178  
1179  		switch (label & IPC_LABEL_SUBST_MASK) {
1180  		case IPC_LABEL_SUBST_TASK:
1181  			subst = ipc_kobject_label_substitute_task(space, port);
1182  			break;
1183  		case IPC_LABEL_SUBST_THREAD:
1184  			subst = ipc_kobject_label_substitute_thread(space, port);
1185  			break;
1186  		case IPC_LABEL_SUBST_ONCE:
1187  			/* the next check will _not_ substitute */
1188  			*flags |= IPC_OBJECT_COPYOUT_FLAGS_NO_LABEL_CHECK;
1189  			subst = ip_get_kobject(port);
1190  			break;
1191  		default:
1192  			panic("unexpected label: %llx\n", label);
1193  		}
1194  
1195  		if (subst != IP_NULL) {
1196  			ip_reference(subst);
1197  			is_write_unlock(space);
1198  			ipc_port_release_send_and_unlock(port);
1199  			port = ipc_port_make_send(subst);
1200  			ip_release(subst);
1201  			*subst_portp = port;
1202  			return true;
1203  		}
1204  	}
1205  
1206  	return (label & space->is_label & IPC_LABEL_SPACE_MASK) ==
1207  	       (label & IPC_LABEL_SPACE_MASK);
1208  }
1209  
1210  boolean_t
1211  ipc_kobject_notify(
1212  	mach_msg_header_t *request_header,
1213  	mach_msg_header_t *reply_header)
1214  {
1215  	mach_msg_max_trailer_t * trailer;
1216  	ipc_port_t port = request_header->msgh_remote_port;
1217  
1218  	((mig_reply_error_t *) reply_header)->RetCode = MIG_NO_REPLY;
1219  
1220  	trailer = (mach_msg_max_trailer_t *)
1221  	    ((vm_offset_t)request_header + request_header->msgh_size);
1222  
1223  	/*
1224  	 * The kobject notification is privileged and can change the
1225  	 * refcount on kernel-internal objects - make sure
1226  	 * that the message wasn't faked!
1227  	 */
1228  	if (0 != bcmp(&trailer->msgh_audit, &KERNEL_AUDIT_TOKEN,
1229  	    sizeof(trailer->msgh_audit))) {
1230  		return FALSE;
1231  	}
1232  	if (0 != bcmp(&trailer->msgh_sender, &KERNEL_SECURITY_TOKEN,
1233  	    sizeof(trailer->msgh_sender))) {
1234  		return FALSE;
1235  	}
1236  
1237  	switch (request_header->msgh_id) {
1238  	case MACH_NOTIFY_NO_SENDERS:
1239  		switch (ip_kotype(port)) {
1240  		case IKOT_VOUCHER:
1241  			ipc_voucher_notify(request_header);
1242  			return TRUE;
1243  
1244  		case IKOT_VOUCHER_ATTR_CONTROL:
1245  			ipc_voucher_attr_control_notify(request_header);
1246  			return TRUE;
1247  
1248  		case IKOT_PORT_SUBST_ONCE:
1249  			ipc_kobject_subst_once_notify(request_header);
1250  			return TRUE;
1251  
1252  		case IKOT_SEMAPHORE:
1253  			semaphore_notify(request_header);
1254  			return TRUE;
1255  
1256  		case IKOT_EVENTLINK:
1257  			ipc_eventlink_notify(request_header);
1258  			return TRUE;
1259  
1260  		case IKOT_TASK_CONTROL:
1261  			task_port_notify(request_header);
1262  			return TRUE;
1263  
1264  		case IKOT_NAMED_ENTRY:
1265  			ip_lock(port);
1266  
1267  			/*
1268  			 * Bring the sequence number and mscount in
1269  			 * line with ipc_port_destroy assertion.
1270  			 */
1271  			port->ip_mscount = 0;
1272  			port->ip_messages.imq_seqno = 0;
1273  			ipc_port_destroy(port);         /* releases lock */
1274  			return TRUE;
1275  
1276  		case IKOT_UPL:
1277  			upl_no_senders(
1278  				request_header->msgh_remote_port,
1279  				(mach_port_mscount_t)
1280  				((mach_no_senders_notification_t *)
1281  				request_header)->not_count);
1282  			reply_header->msgh_remote_port = MACH_PORT_NULL;
1283  			return TRUE;
1284  
1285  #if     CONFIG_AUDIT
1286  		case IKOT_AU_SESSIONPORT:
1287  			audit_session_nosenders(request_header);
1288  			return TRUE;
1289  #endif
1290  		case IKOT_FILEPORT:
1291  			fileport_notify(request_header);
1292  			return TRUE;
1293  
1294  		case IKOT_WORK_INTERVAL:
1295  			work_interval_port_notify(request_header);
1296  			return TRUE;
1297  		case IKOT_TASK_READ:
1298  		case IKOT_TASK_INSPECT:
1299  			task_port_with_flavor_notify(request_header);
1300  			return TRUE;
1301  		case IKOT_THREAD_READ:
1302  		case IKOT_THREAD_INSPECT:
1303  			thread_port_with_flavor_notify(request_header);
1304  			return TRUE;
1305  		case IKOT_SUID_CRED:
1306  			suid_cred_notify(request_header);
1307  			return TRUE;
1308  		case IKOT_TASK_ID_TOKEN:
1309  			task_id_token_notify(request_header);
1310  			return TRUE;
1311  #if HYPERVISOR
1312  		case IKOT_HYPERVISOR:
1313  			hv_port_notify(request_header);
1314  			return TRUE;
1315  #endif
1316  		}
1317  
1318  		break;
1319  
1320  	case MACH_NOTIFY_PORT_DELETED:
1321  	case MACH_NOTIFY_PORT_DESTROYED:
1322  	case MACH_NOTIFY_SEND_ONCE:
1323  	case MACH_NOTIFY_DEAD_NAME:
1324  		break;
1325  
1326  	default:
1327  		return FALSE;
1328  	}
1329  	switch (ip_kotype(port)) {
1330  #ifdef IOKIT
1331  	case IKOT_IOKIT_OBJECT:
1332  	case IKOT_IOKIT_CONNECT:
1333  	case IKOT_IOKIT_IDENT:
1334  	case IKOT_UEXT_OBJECT:
1335  	{
1336  		return iokit_notify(request_header);
1337  	}
1338  #endif
1339  	case IKOT_TASK_RESUME:
1340  	{
1341  		return task_suspension_notify(request_header);
1342  	}
1343  
1344  	default:
1345  		return FALSE;
1346  	}
1347  }