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