]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ipc/ipc_right.c
xnu-2050.7.9.tar.gz
[apple/xnu.git] / osfmk / ipc / ipc_right.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_FREE_COPYRIGHT@
30 */
31 /*
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
34 * All Rights Reserved.
35 *
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
41 *
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45 *
46 * Carnegie Mellon requests users of this software to return to
47 *
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
52 *
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56 /*
57 * NOTICE: This file was modified by McAfee Research in 2004 to introduce
58 * support for mandatory and extensible security protections. This notice
59 * is included in support of clause 2.2 (b) of the Apple Public License,
60 * Version 2.0.
61 * Copyright (c) 2005-2006 SPARTA, Inc.
62 */
63 /*
64 */
65 /*
66 * File: ipc/ipc_right.c
67 * Author: Rich Draves
68 * Date: 1989
69 *
70 * Functions to manipulate IPC capabilities.
71 */
72
73 #include <mach/boolean.h>
74 #include <mach/kern_return.h>
75 #include <mach/port.h>
76 #include <mach/message.h>
77 #include <kern/assert.h>
78 #include <kern/misc_protos.h>
79 #include <ipc/port.h>
80 #include <ipc/ipc_entry.h>
81 #include <ipc/ipc_space.h>
82 #include <ipc/ipc_object.h>
83 #include <ipc/ipc_hash.h>
84 #include <ipc/ipc_port.h>
85 #include <ipc/ipc_pset.h>
86 #include <ipc/ipc_right.h>
87 #include <ipc/ipc_notify.h>
88 #include <ipc/ipc_table.h>
89 #include <security/mac_mach_internal.h>
90
91 /*
92 * Routine: ipc_right_lookup_write
93 * Purpose:
94 * Finds an entry in a space, given the name.
95 * Conditions:
96 * Nothing locked. If successful, the space is write-locked.
97 * Returns:
98 * KERN_SUCCESS Found an entry.
99 * KERN_INVALID_TASK The space is dead.
100 * KERN_INVALID_NAME Name doesn't exist in space.
101 */
102
103 kern_return_t
104 ipc_right_lookup_write(
105 ipc_space_t space,
106 mach_port_name_t name,
107 ipc_entry_t *entryp)
108 {
109 ipc_entry_t entry;
110
111 assert(space != IS_NULL);
112
113 is_write_lock(space);
114
115 if (!is_active(space)) {
116 is_write_unlock(space);
117 return KERN_INVALID_TASK;
118 }
119
120 if ((entry = ipc_entry_lookup(space, name)) == IE_NULL) {
121 is_write_unlock(space);
122 return KERN_INVALID_NAME;
123 }
124
125 *entryp = entry;
126 return KERN_SUCCESS;
127 }
128
129 /*
130 * Routine: ipc_right_lookup_two_write
131 * Purpose:
132 * Like ipc_right_lookup except that it returns two
133 * entries for two different names that were looked
134 * up under the same space lock.
135 * Conditions:
136 * Nothing locked. If successful, the space is write-locked.
137 * Returns:
138 * KERN_INVALID_TASK The space is dead.
139 * KERN_INVALID_NAME Name doesn't exist in space.
140 */
141
142 kern_return_t
143 ipc_right_lookup_two_write(
144 ipc_space_t space,
145 mach_port_name_t name1,
146 ipc_entry_t *entryp1,
147 mach_port_name_t name2,
148 ipc_entry_t *entryp2)
149 {
150 ipc_entry_t entry1;
151 ipc_entry_t entry2;
152
153 assert(space != IS_NULL);
154
155 is_write_lock(space);
156
157 if (!is_active(space)) {
158 is_write_unlock(space);
159 return KERN_INVALID_TASK;
160 }
161
162 if ((entry1 = ipc_entry_lookup(space, name1)) == IE_NULL) {
163 is_write_unlock(space);
164 return KERN_INVALID_NAME;
165 }
166 if ((entry2 = ipc_entry_lookup(space, name2)) == IE_NULL) {
167 is_write_unlock(space);
168 return KERN_INVALID_NAME;
169 }
170 *entryp1 = entry1;
171 *entryp2 = entry2;
172 return KERN_SUCCESS;
173 }
174
175 /*
176 * Routine: ipc_right_reverse
177 * Purpose:
178 * Translate (space, object) -> (name, entry).
179 * Only finds send/receive rights.
180 * Returns TRUE if an entry is found; if so,
181 * the object is locked and active.
182 * Conditions:
183 * The space must be locked (read or write) and active.
184 * Nothing else locked.
185 */
186
187 boolean_t
188 ipc_right_reverse(
189 ipc_space_t space,
190 ipc_object_t object,
191 mach_port_name_t *namep,
192 ipc_entry_t *entryp)
193 {
194 ipc_port_t port;
195 mach_port_name_t name;
196 ipc_entry_t entry;
197
198 /* would switch on io_otype to handle multiple types of object */
199
200 assert(is_active(space));
201 assert(io_otype(object) == IOT_PORT);
202
203 port = (ipc_port_t) object;
204
205 ip_lock(port);
206 if (!ip_active(port)) {
207 ip_unlock(port);
208
209 return FALSE;
210 }
211
212 if (port->ip_receiver == space) {
213 name = port->ip_receiver_name;
214 assert(name != MACH_PORT_NULL);
215
216 entry = ipc_entry_lookup(space, name);
217
218 assert(entry != IE_NULL);
219 assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
220 assert(port == (ipc_port_t) entry->ie_object);
221
222 *namep = name;
223 *entryp = entry;
224 return TRUE;
225 }
226
227 if (ipc_hash_lookup(space, (ipc_object_t) port, namep, entryp)) {
228 assert((entry = *entryp) != IE_NULL);
229 assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_SEND);
230 assert(port == (ipc_port_t) entry->ie_object);
231
232 return TRUE;
233 }
234
235 ip_unlock(port);
236 return FALSE;
237 }
238
239 /*
240 * Routine: ipc_right_dnrequest
241 * Purpose:
242 * Make a dead-name request, returning the previously
243 * registered send-once right. If notify is IP_NULL,
244 * just cancels the previously registered request.
245 *
246 * Conditions:
247 * Nothing locked. May allocate memory.
248 * Only consumes/returns refs if successful.
249 * Returns:
250 * KERN_SUCCESS Made/canceled dead-name request.
251 * KERN_INVALID_TASK The space is dead.
252 * KERN_INVALID_NAME Name doesn't exist in space.
253 * KERN_INVALID_RIGHT Name doesn't denote port/dead rights.
254 * KERN_INVALID_ARGUMENT Name denotes dead name, but
255 * immediate is FALSE or notify is IP_NULL.
256 * KERN_UREFS_OVERFLOW Name denotes dead name, but
257 * generating immediate notif. would overflow urefs.
258 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
259 */
260
261 kern_return_t
262 ipc_right_request_alloc(
263 ipc_space_t space,
264 mach_port_name_t name,
265 boolean_t immediate,
266 boolean_t send_possible,
267 ipc_port_t notify,
268 ipc_port_t *previousp)
269 {
270 ipc_port_request_index_t prev_request;
271 ipc_port_t previous = IP_NULL;
272 ipc_entry_t entry;
273 kern_return_t kr;
274
275 for (;;) {
276 ipc_port_t port = IP_NULL;
277
278 kr = ipc_right_lookup_write(space, name, &entry);
279 if (kr != KERN_SUCCESS)
280 return kr;
281
282 /* space is write-locked and active */
283
284 prev_request = entry->ie_request;
285
286 /* if nothing to do or undo, we're done */
287 if (notify == IP_NULL && prev_request == IE_REQ_NONE) {
288 is_write_unlock(space);
289 *previousp = IP_NULL;
290 return KERN_SUCCESS;
291 }
292
293 /* see if the entry is of proper type for requests */
294 if (entry->ie_bits & MACH_PORT_TYPE_PORT_RIGHTS) {
295 ipc_port_request_index_t new_request;
296
297 port = (ipc_port_t) entry->ie_object;
298 assert(port != IP_NULL);
299
300 if (!ipc_right_check(space, port, name, entry)) {
301 /* port is locked and active */
302
303 /* if no new request, just cancel previous */
304 if (notify == IP_NULL) {
305 if (prev_request != IE_REQ_NONE)
306 previous = ipc_port_request_cancel(port, name, prev_request);
307 ip_unlock(port);
308 entry->ie_request = IE_REQ_NONE;
309 ipc_entry_modified(space, name, entry);
310 is_write_unlock(space);
311 break;
312 }
313
314 /*
315 * send-once rights, kernel objects, and non-full other queues
316 * fire immediately (if immediate specified).
317 */
318 if (send_possible && immediate &&
319 ((entry->ie_bits & MACH_PORT_TYPE_SEND_ONCE) ||
320 port->ip_receiver == ipc_space_kernel || !ip_full(port))) {
321 if (prev_request != IE_REQ_NONE)
322 previous = ipc_port_request_cancel(port, name, prev_request);
323 ip_unlock(port);
324 entry->ie_request = IE_REQ_NONE;
325 ipc_entry_modified(space, name, entry);
326 is_write_unlock(space);
327
328 ipc_notify_send_possible(notify, name);
329 break;
330 }
331
332 /*
333 * If there is a previous request, free it. Any subsequent
334 * allocation cannot fail, thus assuring an atomic swap.
335 */
336 if (prev_request != IE_REQ_NONE)
337 previous = ipc_port_request_cancel(port, name, prev_request);
338
339 kr = ipc_port_request_alloc(port, name, notify,
340 send_possible, immediate,
341 &new_request);
342 if (kr != KERN_SUCCESS) {
343 assert(previous == IP_NULL);
344 is_write_unlock(space);
345
346 kr = ipc_port_request_grow(port, ITS_SIZE_NONE);
347 /* port is unlocked */
348
349 if (kr != KERN_SUCCESS)
350 return kr;
351
352 continue;
353 }
354
355 assert(new_request != IE_REQ_NONE);
356 ip_unlock(port);
357 entry->ie_request = new_request;
358 ipc_entry_modified(space, name, entry);
359 is_write_unlock(space);
360 break;
361 }
362 /* entry may have changed to dead-name by ipc_right_check() */
363
364 }
365
366 /* treat send_possible requests as immediate w.r.t. dead-name */
367 if ((send_possible || immediate) && notify != IP_NULL &&
368 (entry->ie_bits & MACH_PORT_TYPE_DEAD_NAME)) {
369 mach_port_urefs_t urefs = IE_BITS_UREFS(entry->ie_bits);
370
371 assert(urefs > 0);
372
373 if (MACH_PORT_UREFS_OVERFLOW(urefs, 1)) {
374 is_write_unlock(space);
375 if (port != IP_NULL)
376 ip_release(port);
377 return KERN_UREFS_OVERFLOW;
378 }
379
380 (entry->ie_bits)++; /* increment urefs */
381 ipc_entry_modified(space, name, entry);
382 is_write_unlock(space);
383
384 if (port != IP_NULL)
385 ip_release(port);
386
387 ipc_notify_dead_name(notify, name);
388 previous = IP_NULL;
389 break;
390 }
391
392 is_write_unlock(space);
393
394 if (port != IP_NULL)
395 ip_release(port);
396
397 if (entry->ie_bits & MACH_PORT_TYPE_PORT_OR_DEAD)
398 return KERN_INVALID_ARGUMENT;
399 else
400 return KERN_INVALID_RIGHT;
401 }
402
403 *previousp = previous;
404 return KERN_SUCCESS;
405 }
406
407 /*
408 * Routine: ipc_right_request_cancel
409 * Purpose:
410 * Cancel a notification request and return the send-once right.
411 * Afterwards, entry->ie_request == 0.
412 * Conditions:
413 * The space must be write-locked; the port must be locked.
414 * The port must be active; the space doesn't have to be.
415 */
416
417 ipc_port_t
418 ipc_right_request_cancel(
419 __unused ipc_space_t space,
420 ipc_port_t port,
421 mach_port_name_t name,
422 ipc_entry_t entry)
423 {
424 ipc_port_t previous;
425
426 assert(ip_active(port));
427 assert(port == (ipc_port_t) entry->ie_object);
428
429 if (entry->ie_request == IE_REQ_NONE)
430 return IP_NULL;
431
432 previous = ipc_port_request_cancel(port, name, entry->ie_request);
433 entry->ie_request = IE_REQ_NONE;
434 ipc_entry_modified(space, name, entry);
435 return previous;
436 }
437
438 /*
439 * Routine: ipc_right_inuse
440 * Purpose:
441 * Check if an entry is being used.
442 * Returns TRUE if it is.
443 * Conditions:
444 * The space is write-locked and active.
445 * It is unlocked if the entry is inuse.
446 */
447
448 boolean_t
449 ipc_right_inuse(
450 ipc_space_t space,
451 __unused mach_port_name_t name,
452 ipc_entry_t entry)
453 {
454 if (IE_BITS_TYPE(entry->ie_bits) != MACH_PORT_TYPE_NONE) {
455 is_write_unlock(space);
456 return TRUE;
457 }
458 return FALSE;
459 }
460
461 /*
462 * Routine: ipc_right_check
463 * Purpose:
464 * Check if the port has died. If it has,
465 * clean up the entry and return TRUE.
466 * Conditions:
467 * The space is write-locked; the port is not locked.
468 * If returns FALSE, the port is also locked and active.
469 * Otherwise, entry is converted to a dead name.
470 *
471 * Caller is responsible for a reference to port if it
472 * had died (returns TRUE).
473 */
474
475 boolean_t
476 ipc_right_check(
477 ipc_space_t space,
478 ipc_port_t port,
479 mach_port_name_t name,
480 ipc_entry_t entry)
481 {
482 ipc_entry_bits_t bits;
483
484 assert(is_active(space));
485 assert(port == (ipc_port_t) entry->ie_object);
486
487 ip_lock(port);
488 if (ip_active(port))
489 return FALSE;
490 ip_unlock(port);
491
492 /* this was either a pure send right or a send-once right */
493
494 bits = entry->ie_bits;
495 assert((bits & MACH_PORT_TYPE_RECEIVE) == 0);
496 assert(IE_BITS_UREFS(bits) > 0);
497
498 if (bits & MACH_PORT_TYPE_SEND) {
499 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
500 } else {
501 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
502 assert(IE_BITS_UREFS(bits) == 1);
503 }
504
505
506 /* convert entry to dead name */
507
508 if ((bits & MACH_PORT_TYPE_SEND) && !(bits & MACH_PORT_TYPE_RECEIVE))
509 ipc_hash_delete(space, (ipc_object_t)port, name, entry);
510
511 bits = (bits &~ IE_BITS_TYPE_MASK) | MACH_PORT_TYPE_DEAD_NAME;
512
513 /*
514 * If there was a notification request outstanding on this
515 * name, and the port went dead, that notification
516 * must already be on its way up from the port layer.
517 *
518 * Add the reference that the notification carries. It
519 * is done here, and not in the notification delivery,
520 * because the latter doesn't have a space reference and
521 * trying to actually move a send-right reference would
522 * get short-circuited into a MACH_PORT_DEAD by IPC. Since
523 * all calls that deal with the right eventually come
524 * through here, it has the same result.
525 *
526 * Once done, clear the request index so we only account
527 * for it once.
528 */
529 if (entry->ie_request != IE_REQ_NONE) {
530 if (ipc_port_request_type(port, name, entry->ie_request) != 0) {
531 assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX);
532 bits++;
533 }
534 entry->ie_request = IE_REQ_NONE;
535 }
536 entry->ie_bits = bits;
537 entry->ie_object = IO_NULL;
538 ipc_entry_modified(space, name, entry);
539 return TRUE;
540 }
541
542 /*
543 * Routine: ipc_right_terminate
544 * Purpose:
545 * Cleans up an entry in a terminated space.
546 * The entry isn't deallocated or removed
547 * from reverse hash tables.
548 * Conditions:
549 * The space is dead and unlocked.
550 */
551
552 void
553 ipc_right_terminate(
554 ipc_space_t space,
555 mach_port_name_t name,
556 ipc_entry_t entry)
557 {
558 ipc_entry_bits_t bits;
559 mach_port_type_t type;
560
561 bits = entry->ie_bits;
562 type = IE_BITS_TYPE(bits);
563
564 assert(!is_active(space));
565
566 /*
567 * IE_BITS_COMPAT/ipc_right_dncancel doesn't have this
568 * problem, because we check that the port is active. If
569 * we didn't cancel IE_BITS_COMPAT, ipc_port_destroy
570 * would still work, but dead space refs would accumulate
571 * in ip_dnrequests. They would use up slots in
572 * ip_dnrequests and keep the spaces from being freed.
573 */
574
575 switch (type) {
576 case MACH_PORT_TYPE_DEAD_NAME:
577 assert(entry->ie_request == IE_REQ_NONE);
578 assert(entry->ie_object == IO_NULL);
579 break;
580
581 case MACH_PORT_TYPE_PORT_SET: {
582 ipc_pset_t pset = (ipc_pset_t) entry->ie_object;
583
584 assert(entry->ie_request == IE_REQ_NONE);
585 assert(pset != IPS_NULL);
586
587 ips_lock(pset);
588 assert(ips_active(pset));
589 ipc_pset_destroy(pset); /* consumes ref, unlocks */
590 break;
591 }
592
593 case MACH_PORT_TYPE_SEND:
594 case MACH_PORT_TYPE_RECEIVE:
595 case MACH_PORT_TYPE_SEND_RECEIVE:
596 case MACH_PORT_TYPE_SEND_ONCE: {
597 ipc_port_t port = (ipc_port_t) entry->ie_object;
598 ipc_port_t request;
599 ipc_port_t nsrequest = IP_NULL;
600 mach_port_mscount_t mscount = 0;
601
602 assert(port != IP_NULL);
603 ip_lock(port);
604
605 if (!ip_active(port)) {
606 ip_unlock(port);
607 ip_release(port);
608 break;
609 }
610
611 request = ipc_right_request_cancel_macro(space, port,
612 name, entry);
613
614 if (type & MACH_PORT_TYPE_SEND) {
615 assert(port->ip_srights > 0);
616 if (--port->ip_srights == 0
617 ) {
618 nsrequest = port->ip_nsrequest;
619 if (nsrequest != IP_NULL) {
620 port->ip_nsrequest = IP_NULL;
621 mscount = port->ip_mscount;
622 }
623 }
624 }
625
626 if (type & MACH_PORT_TYPE_RECEIVE) {
627 wait_queue_link_t wql;
628 queue_head_t links_data;
629 queue_t links = &links_data;
630
631 assert(port->ip_receiver_name == name);
632 assert(port->ip_receiver == space);
633
634 queue_init(links);
635 ipc_port_clear_receiver(port, links);
636 ipc_port_destroy(port); /* consumes our ref, unlocks */
637 while(!queue_empty(links)) {
638 wql = (wait_queue_link_t) dequeue(links);
639 wait_queue_link_free(wql);
640 }
641
642 } else if (type & MACH_PORT_TYPE_SEND_ONCE) {
643 assert(port->ip_sorights > 0);
644 ip_unlock(port);
645
646 ipc_notify_send_once(port); /* consumes our ref */
647 } else {
648 assert(port->ip_receiver != space);
649
650 ip_unlock(port);
651 ip_release(port);
652 }
653
654 if (nsrequest != IP_NULL)
655 ipc_notify_no_senders(nsrequest, mscount);
656
657 if (request != IP_NULL)
658 ipc_notify_port_deleted(request, name);
659 break;
660 }
661
662 default:
663 panic("ipc_right_terminate: strange type - 0x%x", type);
664 }
665 }
666
667 /*
668 * Routine: ipc_right_destroy
669 * Purpose:
670 * Destroys an entry in a space.
671 * Conditions:
672 * The space is write-locked (returns unlocked).
673 * The space must be active.
674 * Returns:
675 * KERN_SUCCESS The entry was destroyed.
676 */
677
678 kern_return_t
679 ipc_right_destroy(
680 ipc_space_t space,
681 mach_port_name_t name,
682 ipc_entry_t entry)
683 {
684 ipc_entry_bits_t bits;
685 mach_port_type_t type;
686
687 bits = entry->ie_bits;
688 entry->ie_bits &= ~IE_BITS_TYPE_MASK;
689 type = IE_BITS_TYPE(bits);
690
691 assert(is_active(space));
692
693 switch (type) {
694 case MACH_PORT_TYPE_DEAD_NAME:
695 assert(entry->ie_request == IE_REQ_NONE);
696 assert(entry->ie_object == IO_NULL);
697
698 ipc_entry_dealloc(space, name, entry);
699 is_write_unlock(space);
700 break;
701
702 case MACH_PORT_TYPE_PORT_SET: {
703 ipc_pset_t pset = (ipc_pset_t) entry->ie_object;
704
705 assert(entry->ie_request == IE_REQ_NONE);
706 assert(pset != IPS_NULL);
707
708 entry->ie_object = IO_NULL;
709 ipc_entry_dealloc(space, name, entry);
710
711 ips_lock(pset);
712 is_write_unlock(space);
713
714 assert(ips_active(pset));
715 ipc_pset_destroy(pset); /* consumes ref, unlocks */
716 break;
717 }
718
719 case MACH_PORT_TYPE_SEND:
720 case MACH_PORT_TYPE_RECEIVE:
721 case MACH_PORT_TYPE_SEND_RECEIVE:
722 case MACH_PORT_TYPE_SEND_ONCE: {
723 ipc_port_t port = (ipc_port_t) entry->ie_object;
724 ipc_port_t nsrequest = IP_NULL;
725 mach_port_mscount_t mscount = 0;
726 ipc_port_t request;
727
728 assert(port != IP_NULL);
729
730 if (type == MACH_PORT_TYPE_SEND)
731 ipc_hash_delete(space, (ipc_object_t) port,
732 name, entry);
733
734 ip_lock(port);
735
736 if (!ip_active(port)) {
737 assert((type & MACH_PORT_TYPE_RECEIVE) == 0);
738 ip_unlock(port);
739 entry->ie_request = IE_REQ_NONE;
740 entry->ie_object = IO_NULL;
741 ipc_entry_dealloc(space, name, entry);
742 is_write_unlock(space);
743 ip_release(port);
744 break;
745 }
746
747 request = ipc_right_request_cancel_macro(space, port, name, entry);
748
749 entry->ie_object = IO_NULL;
750 ipc_entry_dealloc(space, name, entry);
751 is_write_unlock(space);
752
753 if (type & MACH_PORT_TYPE_SEND) {
754 assert(port->ip_srights > 0);
755 if (--port->ip_srights == 0) {
756 nsrequest = port->ip_nsrequest;
757 if (nsrequest != IP_NULL) {
758 port->ip_nsrequest = IP_NULL;
759 mscount = port->ip_mscount;
760 }
761 }
762 }
763
764 if (type & MACH_PORT_TYPE_RECEIVE) {
765 queue_head_t links_data;
766 queue_t links = &links_data;
767 wait_queue_link_t wql;
768
769 assert(ip_active(port));
770 assert(port->ip_receiver == space);
771
772 queue_init(links);
773 ipc_port_clear_receiver(port, links);
774 ipc_port_destroy(port); /* consumes our ref, unlocks */
775 while(!queue_empty(links)) {
776 wql = (wait_queue_link_t) dequeue(links);
777 wait_queue_link_free(wql);
778 }
779
780 } else if (type & MACH_PORT_TYPE_SEND_ONCE) {
781 assert(port->ip_sorights > 0);
782 ip_unlock(port);
783
784 ipc_notify_send_once(port); /* consumes our ref */
785 } else {
786 assert(port->ip_receiver != space);
787
788 ip_unlock(port);
789 ip_release(port);
790 }
791
792 if (nsrequest != IP_NULL)
793 ipc_notify_no_senders(nsrequest, mscount);
794
795 if (request != IP_NULL)
796 ipc_notify_port_deleted(request, name);
797 break;
798 }
799
800 default:
801 panic("ipc_right_destroy: strange type");
802 }
803
804 return KERN_SUCCESS;
805 }
806
807 /*
808 * Routine: ipc_right_dealloc
809 * Purpose:
810 * Releases a send/send-once/dead-name user ref.
811 * Like ipc_right_delta with a delta of -1,
812 * but looks at the entry to determine the right.
813 * Conditions:
814 * The space is write-locked, and is unlocked upon return.
815 * The space must be active.
816 * Returns:
817 * KERN_SUCCESS A user ref was released.
818 * KERN_INVALID_RIGHT Entry has wrong type.
819 */
820
821 kern_return_t
822 ipc_right_dealloc(
823 ipc_space_t space,
824 mach_port_name_t name,
825 ipc_entry_t entry)
826 {
827 ipc_port_t port = IP_NULL;
828 ipc_entry_bits_t bits;
829 mach_port_type_t type;
830
831 bits = entry->ie_bits;
832 type = IE_BITS_TYPE(bits);
833
834
835 assert(is_active(space));
836
837 switch (type) {
838 case MACH_PORT_TYPE_DEAD_NAME: {
839 dead_name:
840
841 assert(IE_BITS_UREFS(bits) > 0);
842 assert(entry->ie_request == IE_REQ_NONE);
843 assert(entry->ie_object == IO_NULL);
844
845 if (IE_BITS_UREFS(bits) == 1) {
846 ipc_entry_dealloc(space, name, entry);
847 } else {
848 entry->ie_bits = bits-1; /* decrement urefs */
849 ipc_entry_modified(space, name, entry);
850 }
851 is_write_unlock(space);
852
853 /* release any port that got converted to dead name below */
854 if (port != IP_NULL)
855 ip_release(port);
856 break;
857 }
858
859 case MACH_PORT_TYPE_SEND_ONCE: {
860 ipc_port_t request;
861
862 assert(IE_BITS_UREFS(bits) == 1);
863
864 port = (ipc_port_t) entry->ie_object;
865 assert(port != IP_NULL);
866
867 if (ipc_right_check(space, port, name, entry)) {
868
869 bits = entry->ie_bits;
870 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
871 goto dead_name; /* it will release port */
872 }
873 /* port is locked and active */
874
875 assert(port->ip_sorights > 0);
876
877 request = ipc_right_request_cancel_macro(space, port, name, entry);
878 ip_unlock(port);
879
880 entry->ie_object = IO_NULL;
881 ipc_entry_dealloc(space, name, entry);
882
883 is_write_unlock(space);
884
885 ipc_notify_send_once(port);
886
887 if (request != IP_NULL)
888 ipc_notify_port_deleted(request, name);
889 break;
890 }
891
892 case MACH_PORT_TYPE_SEND: {
893 ipc_port_t request = IP_NULL;
894 ipc_port_t nsrequest = IP_NULL;
895 mach_port_mscount_t mscount = 0;
896
897
898 assert(IE_BITS_UREFS(bits) > 0);
899
900 port = (ipc_port_t) entry->ie_object;
901 assert(port != IP_NULL);
902
903 if (ipc_right_check(space, port, name, entry)) {
904 bits = entry->ie_bits;
905 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
906 goto dead_name; /* it will release port */
907 }
908 /* port is locked and active */
909
910 assert(port->ip_srights > 0);
911
912 if (IE_BITS_UREFS(bits) == 1) {
913 if (--port->ip_srights == 0) {
914 nsrequest = port->ip_nsrequest;
915 if (nsrequest != IP_NULL) {
916 port->ip_nsrequest = IP_NULL;
917 mscount = port->ip_mscount;
918 }
919 }
920
921 request = ipc_right_request_cancel_macro(space, port,
922 name, entry);
923 ipc_hash_delete(space, (ipc_object_t) port,
924 name, entry);
925
926 ip_unlock(port);
927 entry->ie_object = IO_NULL;
928 ipc_entry_dealloc(space, name, entry);
929 is_write_unlock(space);
930 ip_release(port);
931
932 } else {
933 ip_unlock(port);
934 entry->ie_bits = bits-1; /* decrement urefs */
935 ipc_entry_modified(space, name, entry);
936 is_write_unlock(space);
937 }
938
939
940 if (nsrequest != IP_NULL)
941 ipc_notify_no_senders(nsrequest, mscount);
942
943 if (request != IP_NULL)
944 ipc_notify_port_deleted(request, name);
945 break;
946 }
947
948 case MACH_PORT_TYPE_SEND_RECEIVE: {
949 ipc_port_t nsrequest = IP_NULL;
950 mach_port_mscount_t mscount = 0;
951
952 assert(IE_BITS_UREFS(bits) > 0);
953
954 port = (ipc_port_t) entry->ie_object;
955 assert(port != IP_NULL);
956
957 ip_lock(port);
958 assert(ip_active(port));
959 assert(port->ip_receiver_name == name);
960 assert(port->ip_receiver == space);
961 assert(port->ip_srights > 0);
962
963 if (IE_BITS_UREFS(bits) == 1) {
964 if (--port->ip_srights == 0) {
965 nsrequest = port->ip_nsrequest;
966 if (nsrequest != IP_NULL) {
967 port->ip_nsrequest = IP_NULL;
968 mscount = port->ip_mscount;
969 }
970 }
971
972 entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK |
973 MACH_PORT_TYPE_SEND);
974 } else
975 entry->ie_bits = bits-1; /* decrement urefs */
976
977 ip_unlock(port);
978
979 ipc_entry_modified(space, name, entry);
980 is_write_unlock(space);
981
982 if (nsrequest != IP_NULL)
983 ipc_notify_no_senders(nsrequest, mscount);
984 break;
985 }
986
987 default:
988 is_write_unlock(space);
989 return KERN_INVALID_RIGHT;
990 }
991
992 return KERN_SUCCESS;
993 }
994
995 /*
996 * Routine: ipc_right_delta
997 * Purpose:
998 * Modifies the user-reference count for a right.
999 * May deallocate the right, if the count goes to zero.
1000 * Conditions:
1001 * The space is write-locked, and is unlocked upon return.
1002 * The space must be active.
1003 * Returns:
1004 * KERN_SUCCESS Count was modified.
1005 * KERN_INVALID_RIGHT Entry has wrong type.
1006 * KERN_INVALID_VALUE Bad delta for the right.
1007 * KERN_UREFS_OVERFLOW OK delta, except would overflow.
1008 */
1009
1010 kern_return_t
1011 ipc_right_delta(
1012 ipc_space_t space,
1013 mach_port_name_t name,
1014 ipc_entry_t entry,
1015 mach_port_right_t right,
1016 mach_port_delta_t delta)
1017 {
1018 ipc_port_t port = IP_NULL;
1019 ipc_entry_bits_t bits;
1020
1021 bits = entry->ie_bits;
1022
1023
1024 /*
1025 * The following is used (for case MACH_PORT_RIGHT_DEAD_NAME) in the
1026 * switch below. It is used to keep track of those cases (in DIPC)
1027 * where we have postponed the dropping of a port reference. Since
1028 * the dropping of the reference could cause the port to disappear
1029 * we postpone doing so when we are holding the space lock.
1030 */
1031
1032 assert(is_active(space));
1033 assert(right < MACH_PORT_RIGHT_NUMBER);
1034
1035 /* Rights-specific restrictions and operations. */
1036
1037 switch (right) {
1038 case MACH_PORT_RIGHT_PORT_SET: {
1039 ipc_pset_t pset;
1040
1041 if ((bits & MACH_PORT_TYPE_PORT_SET) == 0)
1042 goto invalid_right;
1043
1044 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_PORT_SET);
1045 assert(IE_BITS_UREFS(bits) == 0);
1046 assert(entry->ie_request == IE_REQ_NONE);
1047
1048 if (delta == 0)
1049 goto success;
1050
1051 if (delta != -1)
1052 goto invalid_value;
1053
1054 pset = (ipc_pset_t) entry->ie_object;
1055 assert(pset != IPS_NULL);
1056
1057 entry->ie_object = IO_NULL;
1058 ipc_entry_dealloc(space, name, entry);
1059
1060 ips_lock(pset);
1061 assert(ips_active(pset));
1062 is_write_unlock(space);
1063
1064 ipc_pset_destroy(pset); /* consumes ref, unlocks */
1065 break;
1066 }
1067
1068 case MACH_PORT_RIGHT_RECEIVE: {
1069 ipc_port_t request = IP_NULL;
1070 queue_head_t links_data;
1071 queue_t links = &links_data;
1072 wait_queue_link_t wql;
1073
1074 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1075 goto invalid_right;
1076
1077 if (delta == 0)
1078 goto success;
1079
1080 if (delta != -1)
1081 goto invalid_value;
1082
1083 port = (ipc_port_t) entry->ie_object;
1084 assert(port != IP_NULL);
1085
1086 /*
1087 * The port lock is needed for ipc_right_dncancel;
1088 * otherwise, we wouldn't have to take the lock
1089 * until just before dropping the space lock.
1090 */
1091
1092 ip_lock(port);
1093 assert(ip_active(port));
1094 assert(port->ip_receiver_name == name);
1095 assert(port->ip_receiver == space);
1096
1097 if (bits & MACH_PORT_TYPE_SEND) {
1098 assert(IE_BITS_TYPE(bits) ==
1099 MACH_PORT_TYPE_SEND_RECEIVE);
1100 assert(IE_BITS_UREFS(bits) > 0);
1101 assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX);
1102 assert(port->ip_srights > 0);
1103
1104 if (port->ip_pdrequest != NULL) {
1105 /*
1106 * Since another task has requested a
1107 * destroy notification for this port, it
1108 * isn't actually being destroyed - the receive
1109 * right is just being moved to another task.
1110 * Since we still have one or more send rights,
1111 * we need to record the loss of the receive
1112 * right and enter the remaining send right
1113 * into the hash table.
1114 */
1115 ipc_entry_modified(space, name, entry);
1116 entry->ie_bits &= ~MACH_PORT_TYPE_RECEIVE;
1117 ipc_hash_insert(space, (ipc_object_t) port,
1118 name, entry);
1119 ip_reference(port);
1120 } else {
1121 /*
1122 * The remaining send right turns into a
1123 * dead name. Notice we don't decrement
1124 * ip_srights, generate a no-senders notif,
1125 * or use ipc_right_dncancel, because the
1126 * port is destroyed "first".
1127 */
1128 bits &= ~IE_BITS_TYPE_MASK;
1129 bits |= MACH_PORT_TYPE_DEAD_NAME;
1130 if (entry->ie_request) {
1131 entry->ie_request = IE_REQ_NONE;
1132 bits++;
1133 }
1134 entry->ie_bits = bits;
1135 entry->ie_object = IO_NULL;
1136 ipc_entry_modified(space, name, entry);
1137 }
1138 } else {
1139 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
1140 assert(IE_BITS_UREFS(bits) == 0);
1141
1142 request = ipc_right_request_cancel_macro(space, port,
1143 name, entry);
1144 entry->ie_object = IO_NULL;
1145 ipc_entry_dealloc(space, name, entry);
1146 }
1147 is_write_unlock(space);
1148
1149 queue_init(links);
1150 ipc_port_clear_receiver(port, links);
1151 ipc_port_destroy(port); /* consumes ref, unlocks */
1152 while(!queue_empty(links)) {
1153 wql = (wait_queue_link_t) dequeue(links);
1154 wait_queue_link_free(wql);
1155 }
1156
1157 if (request != IP_NULL)
1158 ipc_notify_port_deleted(request, name);
1159 break;
1160 }
1161
1162 case MACH_PORT_RIGHT_SEND_ONCE: {
1163 ipc_port_t request;
1164
1165 if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0)
1166 goto invalid_right;
1167
1168 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1169 assert(IE_BITS_UREFS(bits) == 1);
1170
1171 port = (ipc_port_t) entry->ie_object;
1172 assert(port != IP_NULL);
1173
1174 if (ipc_right_check(space, port, name, entry)) {
1175 assert(!(entry->ie_bits & MACH_PORT_TYPE_SEND_ONCE));
1176 goto invalid_right;
1177 }
1178 /* port is locked and active */
1179
1180 assert(port->ip_sorights > 0);
1181
1182 if ((delta > 0) || (delta < -1)) {
1183 ip_unlock(port);
1184 goto invalid_value;
1185 }
1186
1187 if (delta == 0) {
1188 ip_unlock(port);
1189 goto success;
1190 }
1191
1192 request = ipc_right_request_cancel_macro(space, port, name, entry);
1193 ip_unlock(port);
1194
1195 entry->ie_object = IO_NULL;
1196 ipc_entry_dealloc(space, name, entry);
1197
1198 is_write_unlock(space);
1199
1200 ipc_notify_send_once(port);
1201
1202 if (request != IP_NULL)
1203 ipc_notify_port_deleted(request, name);
1204 break;
1205 }
1206
1207 case MACH_PORT_RIGHT_DEAD_NAME: {
1208 mach_port_urefs_t urefs;
1209
1210 if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
1211
1212 port = (ipc_port_t) entry->ie_object;
1213 assert(port != IP_NULL);
1214
1215 if (!ipc_right_check(space, port, name, entry)) {
1216 /* port is locked and active */
1217 ip_unlock(port);
1218 port = IP_NULL;
1219 goto invalid_right;
1220 }
1221 bits = entry->ie_bits;
1222 } else if ((bits & MACH_PORT_TYPE_DEAD_NAME) == 0)
1223 goto invalid_right;
1224
1225 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
1226 assert(IE_BITS_UREFS(bits) > 0);
1227 assert(entry->ie_object == IO_NULL);
1228 assert(entry->ie_request == IE_REQ_NONE);
1229
1230 urefs = IE_BITS_UREFS(bits);
1231 if (MACH_PORT_UREFS_UNDERFLOW(urefs, delta))
1232 goto invalid_value;
1233 if (MACH_PORT_UREFS_OVERFLOW(urefs, delta))
1234 goto urefs_overflow;
1235
1236 if ((urefs + delta) == 0) {
1237 ipc_entry_dealloc(space, name, entry);
1238 } else {
1239 entry->ie_bits = bits + delta;
1240 ipc_entry_modified(space, name, entry);
1241 }
1242 is_write_unlock(space);
1243
1244 break;
1245 }
1246
1247 case MACH_PORT_RIGHT_SEND: {
1248 mach_port_urefs_t urefs;
1249 ipc_port_t request = IP_NULL;
1250 ipc_port_t nsrequest = IP_NULL;
1251 mach_port_mscount_t mscount = 0;
1252
1253 if ((bits & MACH_PORT_TYPE_SEND) == 0)
1254 goto invalid_right;
1255
1256 /* maximum urefs for send is MACH_PORT_UREFS_MAX-1 */
1257
1258 port = (ipc_port_t) entry->ie_object;
1259 assert(port != IP_NULL);
1260
1261 if (ipc_right_check(space, port, name, entry)) {
1262 assert((entry->ie_bits & MACH_PORT_TYPE_SEND) == 0);
1263 goto invalid_right;
1264 }
1265 /* port is locked and active */
1266
1267 assert(port->ip_srights > 0);
1268
1269 urefs = IE_BITS_UREFS(bits);
1270 if (MACH_PORT_UREFS_UNDERFLOW(urefs, delta)) {
1271 ip_unlock(port);
1272 goto invalid_value;
1273 }
1274 if (MACH_PORT_UREFS_OVERFLOW(urefs+1, delta)) {
1275 ip_unlock(port);
1276 goto urefs_overflow;
1277 }
1278
1279 if ((urefs + delta) == 0) {
1280 if (--port->ip_srights == 0) {
1281 nsrequest = port->ip_nsrequest;
1282 if (nsrequest != IP_NULL) {
1283 port->ip_nsrequest = IP_NULL;
1284 mscount = port->ip_mscount;
1285 }
1286 }
1287
1288 if (bits & MACH_PORT_TYPE_RECEIVE) {
1289 assert(port->ip_receiver_name == name);
1290 assert(port->ip_receiver == space);
1291 ip_unlock(port);
1292 assert(IE_BITS_TYPE(bits) ==
1293 MACH_PORT_TYPE_SEND_RECEIVE);
1294
1295 entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK|
1296 MACH_PORT_TYPE_SEND);
1297 ipc_entry_modified(space, name, entry);
1298 } else {
1299 assert(IE_BITS_TYPE(bits) ==
1300 MACH_PORT_TYPE_SEND);
1301
1302 request = ipc_right_request_cancel_macro(space, port,
1303 name, entry);
1304 ipc_hash_delete(space, (ipc_object_t) port,
1305 name, entry);
1306
1307 ip_unlock(port);
1308 ip_release(port);
1309
1310 entry->ie_object = IO_NULL;
1311 ipc_entry_dealloc(space, name, entry);
1312 }
1313 } else {
1314 ip_unlock(port);
1315 entry->ie_bits = bits + delta;
1316 ipc_entry_modified(space, name, entry);
1317 }
1318
1319 is_write_unlock(space);
1320
1321 if (nsrequest != IP_NULL)
1322 ipc_notify_no_senders(nsrequest, mscount);
1323
1324 if (request != IP_NULL)
1325 ipc_notify_port_deleted(request, name);
1326 break;
1327 }
1328
1329 default:
1330 panic("ipc_right_delta: strange right");
1331 }
1332
1333 return KERN_SUCCESS;
1334
1335 success:
1336 is_write_unlock(space);
1337 return KERN_SUCCESS;
1338
1339 invalid_right:
1340 is_write_unlock(space);
1341 if (port != IP_NULL)
1342 ip_release(port);
1343 return KERN_INVALID_RIGHT;
1344
1345 invalid_value:
1346 is_write_unlock(space);
1347 return KERN_INVALID_VALUE;
1348
1349 urefs_overflow:
1350 is_write_unlock(space);
1351 return KERN_UREFS_OVERFLOW;
1352 }
1353
1354 /*
1355 * Routine: ipc_right_info
1356 * Purpose:
1357 * Retrieves information about the right.
1358 * Conditions:
1359 * The space is active and write-locked.
1360 * The space is unlocked upon return.
1361 * Returns:
1362 * KERN_SUCCESS Retrieved info
1363 */
1364
1365 kern_return_t
1366 ipc_right_info(
1367 ipc_space_t space,
1368 mach_port_name_t name,
1369 ipc_entry_t entry,
1370 mach_port_type_t *typep,
1371 mach_port_urefs_t *urefsp)
1372 {
1373 ipc_port_t port;
1374 ipc_entry_bits_t bits;
1375 mach_port_type_t type = 0;
1376 ipc_port_request_index_t request;
1377
1378 bits = entry->ie_bits;
1379 request = entry->ie_request;
1380 port = (ipc_port_t) entry->ie_object;
1381
1382 if (bits & MACH_PORT_TYPE_RECEIVE) {
1383 assert(IP_VALID(port));
1384
1385 if (request != IE_REQ_NONE) {
1386 ip_lock(port);
1387 assert(ip_active(port));
1388 type |= ipc_port_request_type(port, name, request);
1389 ip_unlock(port);
1390 }
1391 is_write_unlock(space);
1392
1393 } else if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
1394 /*
1395 * validate port is still alive - if so, get request
1396 * types while we still have it locked. Otherwise,
1397 * recapture the (now dead) bits.
1398 */
1399 if (!ipc_right_check(space, port, name, entry)) {
1400 if (request != IE_REQ_NONE)
1401 type |= ipc_port_request_type(port, name, request);
1402 ip_unlock(port);
1403 is_write_unlock(space);
1404 } else {
1405 bits = entry->ie_bits;
1406 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
1407 is_write_unlock(space);
1408 ip_release(port);
1409 }
1410 } else {
1411 is_write_unlock(space);
1412 }
1413
1414 type |= IE_BITS_TYPE(bits);
1415
1416 *typep = type;
1417 *urefsp = IE_BITS_UREFS(bits);
1418 return KERN_SUCCESS;
1419 }
1420
1421 /*
1422 * Routine: ipc_right_copyin_check
1423 * Purpose:
1424 * Check if a subsequent ipc_right_copyin would succeed.
1425 * Conditions:
1426 * The space is locked (read or write) and active.
1427 */
1428
1429 boolean_t
1430 ipc_right_copyin_check(
1431 __assert_only ipc_space_t space,
1432 __unused mach_port_name_t name,
1433 ipc_entry_t entry,
1434 mach_msg_type_name_t msgt_name)
1435 {
1436 ipc_entry_bits_t bits;
1437 ipc_port_t port;
1438 #if CONFIG_MACF_MACH
1439 task_t self = current_task();
1440 int rc = 0;
1441 #endif
1442
1443 bits= entry->ie_bits;
1444 assert(is_active(space));
1445
1446 switch (msgt_name) {
1447 case MACH_MSG_TYPE_MAKE_SEND:
1448 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1449 return FALSE;
1450
1451 #if CONFIG_MACF_MACH
1452 port = (ipc_port_t) entry->ie_object;
1453 ip_lock(port);
1454 tasklabel_lock(self);
1455 rc = mac_port_check_make_send(&self->maclabel, &port->ip_label); tasklabel_unlock(self);
1456 ip_unlock(port);
1457 if (rc)
1458 return FALSE;
1459 #endif
1460 break;
1461
1462 case MACH_MSG_TYPE_MAKE_SEND_ONCE:
1463 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1464 return FALSE;
1465
1466 #if CONFIG_MACF_MACH
1467 port = (ipc_port_t) entry->ie_object;
1468 ip_lock(port);
1469 tasklabel_lock(self);
1470 rc = mac_port_check_make_send_once(&self->maclabel, &port->ip_label);
1471 tasklabel_unlock(self);
1472 ip_unlock(port);
1473 if (rc)
1474 return FALSE;
1475 #endif
1476 break;
1477
1478 case MACH_MSG_TYPE_MOVE_RECEIVE:
1479 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1480 return FALSE;
1481
1482 #if CONFIG_MACF_MACH
1483 port = (ipc_port_t) entry->ie_object;
1484 ip_lock(port);
1485 tasklabel_lock(self);
1486 rc = mac_port_check_move_receive(&self->maclabel, &port->ip_label);
1487 tasklabel_unlock(self);
1488 ip_unlock(port);
1489 if (rc)
1490 return FALSE;
1491 #endif
1492 break;
1493
1494 case MACH_MSG_TYPE_COPY_SEND:
1495 case MACH_MSG_TYPE_MOVE_SEND:
1496 case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
1497 boolean_t active;
1498
1499 if (bits & MACH_PORT_TYPE_DEAD_NAME)
1500 break;
1501
1502 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
1503 return FALSE;
1504
1505 port = (ipc_port_t) entry->ie_object;
1506 assert(port != IP_NULL);
1507
1508 ip_lock(port);
1509 active = ip_active(port);
1510 #if CONFIG_MACF_MACH
1511 tasklabel_lock(self);
1512 switch (msgt_name) {
1513 case MACH_MSG_TYPE_COPY_SEND:
1514 rc = mac_port_check_copy_send(&self->maclabel,
1515 &port->ip_label);
1516 break;
1517 case MACH_MSG_TYPE_MOVE_SEND:
1518 rc = mac_port_check_move_send(&self->maclabel,
1519 &port->ip_label);
1520 break;
1521 case MACH_MSG_TYPE_MOVE_SEND_ONCE:
1522 rc = mac_port_check_move_send_once(&self->maclabel,
1523 &port->ip_label);
1524 break;
1525 default:
1526 panic("ipc_right_copyin_check: strange rights");
1527 }
1528 tasklabel_unlock(self);
1529 if (rc) {
1530 ip_unlock(port);
1531 return FALSE;
1532 }
1533 #endif
1534 ip_unlock(port);
1535
1536 if (!active) {
1537 break;
1538 }
1539
1540 if (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE) {
1541 if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0)
1542 return FALSE;
1543 } else {
1544 if ((bits & MACH_PORT_TYPE_SEND) == 0)
1545 return FALSE;
1546 }
1547
1548 break;
1549 }
1550
1551 default:
1552 panic("ipc_right_copyin_check: strange rights");
1553 }
1554
1555 return TRUE;
1556 }
1557
1558 /*
1559 * Routine: ipc_right_copyin
1560 * Purpose:
1561 * Copyin a capability from a space.
1562 * If successful, the caller gets a ref
1563 * for the resulting object, unless it is IO_DEAD,
1564 * and possibly a send-once right which should
1565 * be used in a port-deleted notification.
1566 *
1567 * If deadok is not TRUE, the copyin operation
1568 * will fail instead of producing IO_DEAD.
1569 *
1570 * The entry is never deallocated (except
1571 * when KERN_INVALID_NAME), so the caller
1572 * should deallocate the entry if its type
1573 * is MACH_PORT_TYPE_NONE.
1574 * Conditions:
1575 * The space is write-locked and active.
1576 * Returns:
1577 * KERN_SUCCESS Acquired an object, possibly IO_DEAD.
1578 * KERN_INVALID_RIGHT Name doesn't denote correct right.
1579 */
1580
1581 kern_return_t
1582 ipc_right_copyin(
1583 ipc_space_t space,
1584 mach_port_name_t name,
1585 ipc_entry_t entry,
1586 mach_msg_type_name_t msgt_name,
1587 boolean_t deadok,
1588 ipc_object_t *objectp,
1589 ipc_port_t *sorightp,
1590 ipc_port_t *releasep,
1591 queue_t links)
1592 {
1593 ipc_entry_bits_t bits;
1594 ipc_port_t port;
1595 #if CONFIG_MACF_MACH
1596 task_t self = current_task();
1597 int rc;
1598 #endif
1599
1600 *releasep = IP_NULL;
1601
1602 bits = entry->ie_bits;
1603
1604 assert(is_active(space));
1605
1606 switch (msgt_name) {
1607 case MACH_MSG_TYPE_MAKE_SEND: {
1608
1609 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1610 goto invalid_right;
1611
1612 port = (ipc_port_t) entry->ie_object;
1613 assert(port != IP_NULL);
1614
1615 ip_lock(port);
1616 assert(ip_active(port));
1617 assert(port->ip_receiver_name == name);
1618 assert(port->ip_receiver == space);
1619
1620 #if CONFIG_MACF_MACH
1621 tasklabel_lock(self);
1622 rc = mac_port_check_make_send(&self->maclabel, &port->ip_label);
1623 tasklabel_unlock(self);
1624 if (rc) {
1625 ip_unlock(port);
1626 return KERN_NO_ACCESS;
1627 }
1628 #endif
1629
1630 port->ip_mscount++;
1631 port->ip_srights++;
1632 ip_reference(port);
1633 ip_unlock(port);
1634
1635 *objectp = (ipc_object_t) port;
1636 *sorightp = IP_NULL;
1637 break;
1638 }
1639
1640 case MACH_MSG_TYPE_MAKE_SEND_ONCE: {
1641
1642 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1643 goto invalid_right;
1644
1645 port = (ipc_port_t) entry->ie_object;
1646 assert(port != IP_NULL);
1647
1648 ip_lock(port);
1649 assert(ip_active(port));
1650 assert(port->ip_receiver_name == name);
1651 assert(port->ip_receiver == space);
1652
1653 #if CONFIG_MACF_MACH
1654 tasklabel_lock(self);
1655 rc = mac_port_check_make_send_once(&self->maclabel, &port->ip_label);
1656 tasklabel_unlock(self);
1657 if (rc) {
1658 ip_unlock(port);
1659 return KERN_NO_ACCESS;
1660 }
1661 #endif
1662
1663 port->ip_sorights++;
1664 ip_reference(port);
1665 ip_unlock(port);
1666
1667 *objectp = (ipc_object_t) port;
1668 *sorightp = IP_NULL;
1669 break;
1670 }
1671
1672 case MACH_MSG_TYPE_MOVE_RECEIVE: {
1673 ipc_port_t request = IP_NULL;
1674
1675 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1676 goto invalid_right;
1677
1678 port = (ipc_port_t) entry->ie_object;
1679 assert(port != IP_NULL);
1680
1681 ip_lock(port);
1682 assert(ip_active(port));
1683 assert(port->ip_receiver_name == name);
1684 assert(port->ip_receiver == space);
1685
1686 #if CONFIG_MACF_MACH
1687 tasklabel_lock(self);
1688 rc = mac_port_check_move_receive(&self->maclabel,
1689 &port->ip_label);
1690 tasklabel_unlock(self);
1691 if (rc) {
1692 ip_unlock(port);
1693 return KERN_NO_ACCESS;
1694 }
1695 #endif
1696
1697 if (bits & MACH_PORT_TYPE_SEND) {
1698 assert(IE_BITS_TYPE(bits) ==
1699 MACH_PORT_TYPE_SEND_RECEIVE);
1700 assert(IE_BITS_UREFS(bits) > 0);
1701 assert(port->ip_srights > 0);
1702
1703 ipc_hash_insert(space, (ipc_object_t) port,
1704 name, entry);
1705 ip_reference(port);
1706 } else {
1707 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
1708 assert(IE_BITS_UREFS(bits) == 0);
1709
1710 request = ipc_right_request_cancel_macro(space, port,
1711 name, entry);
1712 entry->ie_object = IO_NULL;
1713 }
1714 entry->ie_bits = bits &~ MACH_PORT_TYPE_RECEIVE;
1715 ipc_entry_modified(space, name, entry);
1716
1717 ipc_port_clear_receiver(port, links);
1718 port->ip_receiver_name = MACH_PORT_NULL;
1719 port->ip_destination = IP_NULL;
1720 ip_unlock(port);
1721
1722 *objectp = (ipc_object_t) port;
1723 *sorightp = request;
1724 break;
1725 }
1726
1727 case MACH_MSG_TYPE_COPY_SEND: {
1728
1729 if (bits & MACH_PORT_TYPE_DEAD_NAME)
1730 goto copy_dead;
1731
1732 /* allow for dead send-once rights */
1733
1734 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
1735 goto invalid_right;
1736
1737 assert(IE_BITS_UREFS(bits) > 0);
1738
1739 port = (ipc_port_t) entry->ie_object;
1740 assert(port != IP_NULL);
1741
1742 if (ipc_right_check(space, port, name, entry)) {
1743 bits = entry->ie_bits;
1744 *releasep = port;
1745 goto copy_dead;
1746 }
1747 /* port is locked and active */
1748
1749 #if CONFIG_MACF_MACH
1750 tasklabel_lock(self);
1751 rc = mac_port_check_copy_send(&self->maclabel, &port->ip_label);
1752 tasklabel_unlock(self);
1753 if (rc) {
1754 ip_unlock(port);
1755 return KERN_NO_ACCESS;
1756 }
1757 #endif
1758
1759 if ((bits & MACH_PORT_TYPE_SEND) == 0) {
1760 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1761 assert(port->ip_sorights > 0);
1762
1763 ip_unlock(port);
1764 goto invalid_right;
1765 }
1766
1767 assert(port->ip_srights > 0);
1768
1769 port->ip_srights++;
1770 ip_reference(port);
1771 ip_unlock(port);
1772
1773 *objectp = (ipc_object_t) port;
1774 *sorightp = IP_NULL;
1775 break;
1776 }
1777
1778 case MACH_MSG_TYPE_MOVE_SEND: {
1779 ipc_port_t request = IP_NULL;
1780
1781 if (bits & MACH_PORT_TYPE_DEAD_NAME)
1782 goto move_dead;
1783
1784 /* allow for dead send-once rights */
1785
1786 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
1787 goto invalid_right;
1788
1789 assert(IE_BITS_UREFS(bits) > 0);
1790
1791 port = (ipc_port_t) entry->ie_object;
1792 assert(port != IP_NULL);
1793
1794 if (ipc_right_check(space, port, name, entry)) {
1795 bits = entry->ie_bits;
1796 *releasep = port;
1797 goto move_dead;
1798 }
1799 /* port is locked and active */
1800
1801 #if CONFIG_MACF_MACH
1802 tasklabel_lock (self);
1803 rc = mac_port_check_copy_send (&self->maclabel, &port->ip_label);
1804 tasklabel_unlock (self);
1805 if (rc)
1806 {
1807 ip_unlock (port);
1808 return KERN_NO_ACCESS;
1809 }
1810 #endif
1811
1812 if ((bits & MACH_PORT_TYPE_SEND) == 0) {
1813 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1814 assert(port->ip_sorights > 0);
1815
1816 ip_unlock(port);
1817 goto invalid_right;
1818 }
1819
1820 assert(port->ip_srights > 0);
1821
1822 if (IE_BITS_UREFS(bits) == 1) {
1823 if (bits & MACH_PORT_TYPE_RECEIVE) {
1824 assert(port->ip_receiver_name == name);
1825 assert(port->ip_receiver == space);
1826 assert(IE_BITS_TYPE(bits) ==
1827 MACH_PORT_TYPE_SEND_RECEIVE);
1828
1829 ip_reference(port);
1830 } else {
1831 assert(IE_BITS_TYPE(bits) ==
1832 MACH_PORT_TYPE_SEND);
1833
1834 request = ipc_right_request_cancel_macro(space, port,
1835 name, entry);
1836 ipc_hash_delete(space, (ipc_object_t) port,
1837 name, entry);
1838 entry->ie_object = IO_NULL;
1839 }
1840 entry->ie_bits = bits &~
1841 (IE_BITS_UREFS_MASK|MACH_PORT_TYPE_SEND);
1842 } else {
1843 port->ip_srights++;
1844 ip_reference(port);
1845 entry->ie_bits = bits-1; /* decrement urefs */
1846 }
1847 ipc_entry_modified(space, name, entry);
1848 ip_unlock(port);
1849
1850 *objectp = (ipc_object_t) port;
1851 *sorightp = request;
1852 break;
1853 }
1854
1855 case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
1856 ipc_port_t request;
1857
1858 if (bits & MACH_PORT_TYPE_DEAD_NAME)
1859 goto move_dead;
1860
1861 /* allow for dead send rights */
1862
1863 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
1864 goto invalid_right;
1865
1866 assert(IE_BITS_UREFS(bits) > 0);
1867
1868 port = (ipc_port_t) entry->ie_object;
1869 assert(port != IP_NULL);
1870
1871 if (ipc_right_check(space, port, name, entry)) {
1872 bits = entry->ie_bits;
1873 goto move_dead;
1874 }
1875 /* port is locked and active */
1876
1877 #if CONFIG_MACF_MACH
1878 tasklabel_lock (self);
1879 rc = mac_port_check_copy_send (&self->maclabel, &port->ip_label);
1880 tasklabel_unlock (self);
1881 if (rc)
1882 {
1883 ip_unlock (port);
1884 return KERN_NO_ACCESS;
1885 }
1886 #endif
1887
1888 if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0) {
1889 assert(bits & MACH_PORT_TYPE_SEND);
1890 assert(port->ip_srights > 0);
1891
1892 ip_unlock(port);
1893 goto invalid_right;
1894 }
1895
1896 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1897 assert(IE_BITS_UREFS(bits) == 1);
1898 assert(port->ip_sorights > 0);
1899
1900 request = ipc_right_request_cancel_macro(space, port, name, entry);
1901 ip_unlock(port);
1902
1903 entry->ie_object = IO_NULL;
1904 entry->ie_bits = bits &~
1905 (IE_BITS_UREFS_MASK | MACH_PORT_TYPE_SEND_ONCE);
1906 ipc_entry_modified(space, name, entry);
1907 *objectp = (ipc_object_t) port;
1908 *sorightp = request;
1909 break;
1910 }
1911
1912 default:
1913 invalid_right:
1914 return KERN_INVALID_RIGHT;
1915 }
1916
1917 return KERN_SUCCESS;
1918
1919 copy_dead:
1920 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
1921 assert(IE_BITS_UREFS(bits) > 0);
1922 assert(entry->ie_request == IE_REQ_NONE);
1923 assert(entry->ie_object == 0);
1924
1925 if (!deadok)
1926 goto invalid_right;
1927
1928 *objectp = IO_DEAD;
1929 *sorightp = IP_NULL;
1930 return KERN_SUCCESS;
1931
1932 move_dead:
1933 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
1934 assert(IE_BITS_UREFS(bits) > 0);
1935 assert(entry->ie_request == IE_REQ_NONE);
1936 assert(entry->ie_object == 0);
1937
1938 if (!deadok)
1939 goto invalid_right;
1940
1941 if (IE_BITS_UREFS(bits) == 1) {
1942 bits &= ~MACH_PORT_TYPE_DEAD_NAME;
1943 }
1944 entry->ie_bits = bits-1; /* decrement urefs */
1945 ipc_entry_modified(space, name, entry);
1946 *objectp = IO_DEAD;
1947 *sorightp = IP_NULL;
1948 return KERN_SUCCESS;
1949
1950 }
1951
1952 /*
1953 * Routine: ipc_right_copyin_undo
1954 * Purpose:
1955 * Undoes the effects of an ipc_right_copyin
1956 * of a send/send-once right that is dead.
1957 * (Object is either IO_DEAD or a dead port.)
1958 * Conditions:
1959 * The space is write-locked and active.
1960 */
1961
1962 void
1963 ipc_right_copyin_undo(
1964 ipc_space_t space,
1965 mach_port_name_t name,
1966 ipc_entry_t entry,
1967 mach_msg_type_name_t msgt_name,
1968 ipc_object_t object,
1969 ipc_port_t soright)
1970 {
1971 ipc_entry_bits_t bits;
1972
1973 bits = entry->ie_bits;
1974
1975 assert(is_active(space));
1976
1977 assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
1978 (msgt_name == MACH_MSG_TYPE_COPY_SEND) ||
1979 (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
1980
1981 if (soright != IP_NULL) {
1982 assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
1983 (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
1984 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
1985 assert(object != IO_DEAD);
1986
1987 entry->ie_bits = ((bits &~ IE_BITS_RIGHT_MASK) |
1988 MACH_PORT_TYPE_DEAD_NAME | 2);
1989
1990 } else if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE) {
1991 assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
1992 (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
1993
1994 entry->ie_bits = ((bits &~ IE_BITS_RIGHT_MASK) |
1995 MACH_PORT_TYPE_DEAD_NAME | 1);
1996 } else if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME) {
1997 assert(object == IO_DEAD);
1998 assert(IE_BITS_UREFS(bits) > 0);
1999
2000 if (msgt_name != MACH_MSG_TYPE_COPY_SEND) {
2001 assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX);
2002 entry->ie_bits = bits+1; /* increment urefs */
2003 }
2004 } else {
2005 assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
2006 (msgt_name == MACH_MSG_TYPE_COPY_SEND));
2007 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
2008 assert(object != IO_DEAD);
2009 assert(entry->ie_object == object);
2010 assert(IE_BITS_UREFS(bits) > 0);
2011
2012 if (msgt_name != MACH_MSG_TYPE_COPY_SEND) {
2013 assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX-1);
2014 entry->ie_bits = bits+1; /* increment urefs */
2015 }
2016
2017 /*
2018 * May as well convert the entry to a dead name.
2019 * (Or if it is a compat entry, destroy it.)
2020 */
2021
2022 (void) ipc_right_check(space, (ipc_port_t) object,
2023 name, entry);
2024 /* object is dead so it is not locked */
2025 }
2026 ipc_entry_modified(space, name, entry);
2027 /* release the reference acquired by copyin */
2028
2029 if (object != IO_DEAD)
2030 io_release(object);
2031 }
2032
2033 /*
2034 * Routine: ipc_right_copyin_two
2035 * Purpose:
2036 * Like ipc_right_copyin with MACH_MSG_TYPE_MOVE_SEND
2037 * and deadok == FALSE, except that this moves two
2038 * send rights at once.
2039 * Conditions:
2040 * The space is write-locked and active.
2041 * The object is returned with two refs/send rights.
2042 * Returns:
2043 * KERN_SUCCESS Acquired an object.
2044 * KERN_INVALID_RIGHT Name doesn't denote correct right.
2045 */
2046
2047 kern_return_t
2048 ipc_right_copyin_two(
2049 ipc_space_t space,
2050 mach_port_name_t name,
2051 ipc_entry_t entry,
2052 ipc_object_t *objectp,
2053 ipc_port_t *sorightp,
2054 ipc_port_t *releasep)
2055 {
2056 ipc_entry_bits_t bits;
2057 mach_port_urefs_t urefs;
2058 ipc_port_t port;
2059 ipc_port_t request = IP_NULL;
2060 #if CONFIG_MACF_MACH
2061 task_t self = current_task();
2062 int rc;
2063 #endif
2064
2065 *releasep = IP_NULL;
2066
2067 assert(is_active(space));
2068
2069 bits = entry->ie_bits;
2070
2071 if ((bits & MACH_PORT_TYPE_SEND) == 0)
2072 goto invalid_right;
2073
2074 urefs = IE_BITS_UREFS(bits);
2075 if (urefs < 2)
2076 goto invalid_right;
2077
2078 port = (ipc_port_t) entry->ie_object;
2079 assert(port != IP_NULL);
2080
2081 if (ipc_right_check(space, port, name, entry)) {
2082 *releasep = port;
2083 goto invalid_right;
2084 }
2085 /* port is locked and active */
2086
2087 #if CONFIG_MACF_MACH
2088 tasklabel_lock(self);
2089 rc = mac_port_check_copy_send(&self->maclabel, &port->ip_label);
2090 tasklabel_unlock(self);
2091 if (rc) {
2092 ip_unlock(port);
2093 return KERN_NO_ACCESS;
2094 }
2095 #endif
2096
2097 assert(port->ip_srights > 0);
2098
2099 if (urefs == 2) {
2100 if (bits & MACH_PORT_TYPE_RECEIVE) {
2101 assert(port->ip_receiver_name == name);
2102 assert(port->ip_receiver == space);
2103 assert(IE_BITS_TYPE(bits) ==
2104 MACH_PORT_TYPE_SEND_RECEIVE);
2105
2106 port->ip_srights++;
2107 ip_reference(port);
2108 ip_reference(port);
2109 } else {
2110 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
2111
2112 request = ipc_right_request_cancel_macro(space, port,
2113 name, entry);
2114
2115 port->ip_srights++;
2116 ip_reference(port);
2117 ipc_hash_delete(space, (ipc_object_t) port,
2118 name, entry);
2119 entry->ie_object = IO_NULL;
2120 }
2121 entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK|MACH_PORT_TYPE_SEND);
2122 } else {
2123 port->ip_srights += 2;
2124 ip_reference(port);
2125 ip_reference(port);
2126 entry->ie_bits = bits-2; /* decrement urefs */
2127 }
2128 ipc_entry_modified(space, name, entry);
2129
2130 ip_unlock(port);
2131
2132 *objectp = (ipc_object_t) port;
2133 *sorightp = request;
2134 return KERN_SUCCESS;
2135
2136 invalid_right:
2137 return KERN_INVALID_RIGHT;
2138 }
2139
2140 /*
2141 * Routine: ipc_right_copyout
2142 * Purpose:
2143 * Copyout a capability to a space.
2144 * If successful, consumes a ref for the object.
2145 *
2146 * Always succeeds when given a newly-allocated entry,
2147 * because user-reference overflow isn't a possibility.
2148 *
2149 * If copying out the object would cause the user-reference
2150 * count in the entry to overflow, and overflow is TRUE,
2151 * then instead the user-reference count is left pegged
2152 * to its maximum value and the copyout succeeds anyway.
2153 * Conditions:
2154 * The space is write-locked and active.
2155 * The object is locked and active.
2156 * The object is unlocked; the space isn't.
2157 * Returns:
2158 * KERN_SUCCESS Copied out capability.
2159 * KERN_UREFS_OVERFLOW User-refs would overflow;
2160 * guaranteed not to happen with a fresh entry
2161 * or if overflow=TRUE was specified.
2162 */
2163
2164 kern_return_t
2165 ipc_right_copyout(
2166 ipc_space_t space,
2167 mach_port_name_t name,
2168 ipc_entry_t entry,
2169 mach_msg_type_name_t msgt_name,
2170 boolean_t overflow,
2171 ipc_object_t object)
2172 {
2173 ipc_entry_bits_t bits;
2174 ipc_port_t port;
2175 #if CONFIG_MACF_MACH
2176 int rc;
2177 #endif
2178
2179 bits = entry->ie_bits;
2180
2181 assert(IO_VALID(object));
2182 assert(io_otype(object) == IOT_PORT);
2183 assert(io_active(object));
2184 assert(entry->ie_object == object);
2185
2186 port = (ipc_port_t) object;
2187
2188 switch (msgt_name) {
2189 case MACH_MSG_TYPE_PORT_SEND_ONCE:
2190
2191 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
2192 assert(port->ip_sorights > 0);
2193
2194 #if CONFIG_MACF_MACH
2195 if (space->is_task) {
2196 tasklabel_lock(space->is_task);
2197 rc = mac_port_check_hold_send_once(&space->is_task->maclabel,
2198 &port->ip_label);
2199 tasklabel_unlock(space->is_task);
2200
2201 if (rc) {
2202 ip_unlock(port);
2203 return KERN_NO_ACCESS;
2204 }
2205 }
2206 #endif
2207 /* transfer send-once right and ref to entry */
2208 ip_unlock(port);
2209
2210 entry->ie_bits = bits | (MACH_PORT_TYPE_SEND_ONCE | 1);
2211 ipc_entry_modified(space, name, entry);
2212 break;
2213
2214 case MACH_MSG_TYPE_PORT_SEND:
2215 assert(port->ip_srights > 0);
2216
2217 #if CONFIG_MACF_MACH
2218 if (space->is_task) {
2219 tasklabel_lock(space->is_task);
2220 rc = mac_port_check_hold_send(&space->is_task->maclabel,
2221 &port->ip_label);
2222 tasklabel_unlock(space->is_task);
2223
2224 if (rc) {
2225 ip_unlock(port);
2226 return KERN_NO_ACCESS;
2227 }
2228 }
2229 #endif
2230
2231 if (bits & MACH_PORT_TYPE_SEND) {
2232 mach_port_urefs_t urefs = IE_BITS_UREFS(bits);
2233
2234 assert(port->ip_srights > 1);
2235 assert(urefs > 0);
2236 assert(urefs < MACH_PORT_UREFS_MAX);
2237
2238 if (urefs+1 == MACH_PORT_UREFS_MAX) {
2239 if (overflow) {
2240 /* leave urefs pegged to maximum */
2241
2242 port->ip_srights--;
2243 ip_unlock(port);
2244 ip_release(port);
2245 return KERN_SUCCESS;
2246 }
2247
2248 ip_unlock(port);
2249 return KERN_UREFS_OVERFLOW;
2250 }
2251 port->ip_srights--;
2252 ip_unlock(port);
2253 ip_release(port);
2254
2255 } else if (bits & MACH_PORT_TYPE_RECEIVE) {
2256 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
2257 assert(IE_BITS_UREFS(bits) == 0);
2258
2259 /* transfer send right to entry */
2260 ip_unlock(port);
2261 ip_release(port);
2262
2263 } else {
2264 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
2265 assert(IE_BITS_UREFS(bits) == 0);
2266
2267 /* transfer send right and ref to entry */
2268 ip_unlock(port);
2269
2270 /* entry is locked holding ref, so can use port */
2271
2272 ipc_hash_insert(space, (ipc_object_t) port,
2273 name, entry);
2274 }
2275
2276 entry->ie_bits = (bits | MACH_PORT_TYPE_SEND) + 1;
2277 ipc_entry_modified(space, name, entry);
2278 break;
2279
2280 case MACH_MSG_TYPE_PORT_RECEIVE: {
2281 ipc_port_t dest;
2282
2283 assert(port->ip_mscount == 0);
2284 assert(port->ip_receiver_name == MACH_PORT_NULL);
2285 dest = port->ip_destination;
2286
2287 #if CONFIG_MACF_MACH
2288 if (space->is_task) {
2289 tasklabel_lock(space->is_task);
2290 rc = mac_port_check_hold_receive(&space->is_task->maclabel,
2291 &port->ip_label);
2292 tasklabel_unlock(space->is_task);
2293
2294 if (rc) {
2295 ip_unlock(port);
2296 return KERN_NO_ACCESS;
2297 }
2298 }
2299 #endif
2300
2301 port->ip_receiver_name = name;
2302 port->ip_receiver = space;
2303
2304 assert((bits & MACH_PORT_TYPE_RECEIVE) == 0);
2305
2306 if (bits & MACH_PORT_TYPE_SEND) {
2307 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
2308 assert(IE_BITS_UREFS(bits) > 0);
2309 assert(port->ip_srights > 0);
2310
2311 ip_unlock(port);
2312 ip_release(port);
2313
2314 /* entry is locked holding ref, so can use port */
2315
2316 ipc_hash_delete(space, (ipc_object_t) port,
2317 name, entry);
2318 } else {
2319 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
2320 assert(IE_BITS_UREFS(bits) == 0);
2321
2322 /* transfer ref to entry */
2323 ip_unlock(port);
2324 }
2325 entry->ie_bits = bits | MACH_PORT_TYPE_RECEIVE;
2326 ipc_entry_modified(space, name, entry);
2327
2328 if (dest != IP_NULL)
2329 ip_release(dest);
2330 break;
2331 }
2332
2333 default:
2334 panic("ipc_right_copyout: strange rights");
2335 }
2336
2337 return KERN_SUCCESS;
2338 }
2339
2340 /*
2341 * Routine: ipc_right_rename
2342 * Purpose:
2343 * Transfer an entry from one name to another.
2344 * The old entry is deallocated.
2345 * Conditions:
2346 * The space is write-locked and active.
2347 * The new entry is unused. Upon return,
2348 * the space is unlocked.
2349 * Returns:
2350 * KERN_SUCCESS Moved entry to new name.
2351 */
2352
2353 kern_return_t
2354 ipc_right_rename(
2355 ipc_space_t space,
2356 mach_port_name_t oname,
2357 ipc_entry_t oentry,
2358 mach_port_name_t nname,
2359 ipc_entry_t nentry)
2360 {
2361 ipc_port_request_index_t request = oentry->ie_request;
2362 ipc_entry_bits_t bits = oentry->ie_bits;
2363 ipc_object_t object = oentry->ie_object;
2364 ipc_port_t release_port = IP_NULL;
2365
2366 assert(is_active(space));
2367 assert(oname != nname);
2368
2369 /*
2370 * If IE_BITS_COMPAT, we can't allow the entry to be renamed
2371 * if the port is dead. (This would foil ipc_port_destroy.)
2372 * Instead we should fail because oentry shouldn't exist.
2373 * Note IE_BITS_COMPAT implies ie_request != 0.
2374 */
2375
2376 if (request != IE_REQ_NONE) {
2377 ipc_port_t port;
2378
2379 assert(bits & MACH_PORT_TYPE_PORT_RIGHTS);
2380 port = (ipc_port_t) object;
2381 assert(port != IP_NULL);
2382
2383 if (ipc_right_check(space, port, oname, oentry)) {
2384 request = IE_REQ_NONE;
2385 object = IO_NULL;
2386 bits = oentry->ie_bits;
2387 release_port = port;
2388 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
2389 assert(oentry->ie_request == IE_REQ_NONE);
2390 } else {
2391 /* port is locked and active */
2392
2393 ipc_port_request_rename(port, request, oname, nname);
2394 ip_unlock(port);
2395 oentry->ie_request = IE_REQ_NONE;
2396 }
2397 }
2398
2399 /* initialize nentry before letting ipc_hash_insert see it */
2400
2401 assert((nentry->ie_bits & IE_BITS_RIGHT_MASK) == 0);
2402 nentry->ie_bits |= bits & IE_BITS_RIGHT_MASK;
2403 nentry->ie_request = request;
2404 nentry->ie_object = object;
2405
2406 switch (IE_BITS_TYPE(bits)) {
2407 case MACH_PORT_TYPE_SEND: {
2408 ipc_port_t port;
2409
2410 port = (ipc_port_t) object;
2411 assert(port != IP_NULL);
2412
2413 /* remember, there are no other share entries possible */
2414 /* or we can't do the rename. Therefore we do not need */
2415 /* to check the other subspaces */
2416 ipc_hash_delete(space, (ipc_object_t) port, oname, oentry);
2417 ipc_hash_insert(space, (ipc_object_t) port, nname, nentry);
2418 break;
2419 }
2420
2421 case MACH_PORT_TYPE_RECEIVE:
2422 case MACH_PORT_TYPE_SEND_RECEIVE: {
2423 ipc_port_t port;
2424
2425 port = (ipc_port_t) object;
2426 assert(port != IP_NULL);
2427
2428 ip_lock(port);
2429 assert(ip_active(port));
2430 assert(port->ip_receiver_name == oname);
2431 assert(port->ip_receiver == space);
2432
2433 port->ip_receiver_name = nname;
2434 ip_unlock(port);
2435 break;
2436 }
2437
2438 case MACH_PORT_TYPE_PORT_SET: {
2439 ipc_pset_t pset;
2440
2441 pset = (ipc_pset_t) object;
2442 assert(pset != IPS_NULL);
2443
2444 ips_lock(pset);
2445 assert(ips_active(pset));
2446 assert(pset->ips_local_name == oname);
2447
2448 pset->ips_local_name = nname;
2449 ips_unlock(pset);
2450 break;
2451 }
2452
2453 case MACH_PORT_TYPE_SEND_ONCE:
2454 case MACH_PORT_TYPE_DEAD_NAME:
2455 break;
2456
2457 default:
2458 panic("ipc_right_rename: strange rights");
2459 }
2460
2461 assert(oentry->ie_request == IE_REQ_NONE);
2462 oentry->ie_object = IO_NULL;
2463 ipc_entry_dealloc(space, oname, oentry);
2464 ipc_entry_modified(space, nname, nentry);
2465 is_write_unlock(space);
2466
2467 if (release_port != IP_NULL)
2468 ip_release(release_port);
2469
2470 return KERN_SUCCESS;
2471 }