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