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