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