1 /*
2 * Copyright 1991-1998 by Open Software Foundation, Inc.
3 * All Rights Reserved
4 *
5 * Permission to use, copy, modify, and distribute this software and
6 * its documentation for any purpose and without fee is hereby granted,
7 * provided that the above copyright notice appears in all copies and
8 * that both the copyright notice and this permission notice appear in
9 * supporting documentation.
10 *
11 * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
12 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13 * FOR A PARTICULAR PURPOSE.
14 *
15 * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
16 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
17 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
18 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
19 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 */
21 /*
22 * MkLinux
23 */
24 /* CMU_HIST */
25 /*
26 * Revision 2.6 91/05/14 16:36:12 mrt
27 * Correcting copyright
28 *
29 * Revision 2.5 91/02/14 14:08:29 mrt
30 * Fixed bug in ipc_right_copyin_check, following rchen's report.
31 * [91/01/26 rpd]
32 *
33 * Revision 2.4 91/02/05 17:23:26 mrt
34 * Changed to new Mach copyright
35 * [91/02/01 15:50:46 mrt]
36 *
37 * Revision 2.3 90/11/05 14:30:05 rpd
38 * Changed io_release to ipc_object_release.
39 * Changed ip_release to ipc_port_release.
40 * Use new ip_reference and ip_release.
41 * [90/10/29 rpd]
42 *
43 * Revision 2.2 90/06/02 14:51:28 rpd
44 * Created for new IPC.
45 * [90/03/26 21:02:31 rpd]
46 *
47 */
48 /* CMU_ENDHIST */
49 /*
50 * Mach Operating System
51 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
52 * All Rights Reserved.
53 *
54 * Permission to use, copy, modify and distribute this software and its
55 * documentation is hereby granted, provided that both the copyright
56 * notice and this permission notice appear in all copies of the
57 * software, derivative works or modified versions, and any portions
58 * thereof, and that both notices appear in supporting documentation.
59 *
60 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
61 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
62 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
63 *
64 * Carnegie Mellon requests users of this software to return to
65 *
66 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
67 * School of Computer Science
68 * Carnegie Mellon University
69 * Pittsburgh PA 15213-3890
70 *
71 * any improvements or extensions that they make and grant Carnegie Mellon
72 * the rights to redistribute these changes.
73 */
74 /*
75 */
76 /*
77 * File: ipc/ipc_right.c
78 * Author: Rich Draves
79 * Date: 1989
80 *
81 * Functions to manipulate IPC capabilities.
82 */
83
84
85 #include <sys/cdefs.h>
86 #include <sys/types.h>
87 #include <sys/param.h>
88
89 #include <sys/mach/kern_return.h>
90 #include <sys/mach/port.h>
91 #include <sys/mach/message.h>
92 #if 0
93 #include <kern/assert.h>
94 #include <kern/misc_protos.h>
95 #include <kern/ipc_subsystem.h>
96 #endif
97 #include <sys/mach/ipc/port.h>
98 #include <sys/mach/ipc/ipc_entry.h>
99 #include <sys/mach/ipc/ipc_space.h>
100 #include <sys/mach/ipc/ipc_object.h>
101 #include <sys/mach/ipc/ipc_hash.h>
102 #include <sys/mach/ipc/ipc_port.h>
103 #include <sys/mach/ipc/ipc_pset.h>
104 #include <sys/mach/ipc/ipc_right.h>
105 #include <sys/mach/ipc/ipc_notify.h>
106 #include <sys/mach/ipc/ipc_table.h>
107
108 #include <sys/mach/task.h>
109
110 #ifdef INVARIANTS
111 #define OBJECT_CLEAR(entry, name) do { \
112 /* printf("clearing object %p name: %d %s:%d\n", entry->ie_object, name, __FILE__, __LINE__); */ \
113 (entry)->ie_object = IO_NULL; \
114 } while (0)
115 #else
116 #define OBJECT_CLEAR(entry, name) (entry)->ie_object = IO_NULL
117 #endif
118
119 /*
120 * Routine: ipc_right_lookup_write
121 * Purpose:
122 * Finds an entry in a space, given the name.
123 * Conditions:
124 * Nothing locked. If successful, the space is write-locked.
125 * Returns:
126 * KERN_SUCCESS Found an entry.
127 * KERN_INVALID_TASK The space is dead.
128 * KERN_INVALID_NAME Name doesn't exist in space.
129 */
130
131 kern_return_t
ipc_right_lookup(ipc_space_t space,mach_port_name_t name,ipc_entry_t * entryp,int xlock)132 ipc_right_lookup(
133 ipc_space_t space,
134 mach_port_name_t name,
135 ipc_entry_t *entryp,
136 int xlock)
137 {
138 ipc_entry_t entry;
139
140
141 assert(space != IS_NULL);
142
143
144 if (!space->is_active)
145 return KERN_INVALID_TASK;
146 if ((entry = ipc_entry_lookup(space, name)) == IE_NULL)
147 return KERN_INVALID_NAME;
148
149 if (xlock)
150 is_write_lock(space);
151 else
152 is_read_lock(space);
153 *entryp = entry;
154 return KERN_SUCCESS;
155 }
156
157 /*
158 * Routine: ipc_right_reverse
159 * Purpose:
160 * Translate (space, object) -> (name, entry).
161 * Only finds send/receive rights.
162 * Returns TRUE if an entry is found; if so,
163 * the object is locked and active.
164 * Conditions:
165 * The space must be locked (read or write) and active.
166 * Nothing else locked.
167 */
168
169 boolean_t
ipc_right_reverse(ipc_space_t space,ipc_object_t object,mach_port_name_t * namep,ipc_entry_t * entryp)170 ipc_right_reverse(
171 ipc_space_t space,
172 ipc_object_t object,
173 mach_port_name_t *namep,
174 ipc_entry_t *entryp)
175 {
176 ipc_port_t port;
177 mach_port_name_t name;
178 ipc_entry_t entry;
179
180 /* would switch on io_otype to handle multiple types of object */
181
182 assert(space->is_active);
183 assert(io_otype(object) == IOT_PORT);
184
185 port = (ipc_port_t) object;
186
187 ip_lock(port);
188 if (!ip_active(port)) {
189 ip_unlock(port);
190
191 return FALSE;
192 }
193
194 if (port->ip_receiver == space) {
195 name = port->ip_receiver_name;
196 assert(name != MACH_PORT_NAME_NULL);
197
198 entry = ipc_entry_lookup(space, name);
199
200 KASSERT(entry != IE_NULL, ("no entry found for port: %p name: %d space: %p", port, name, space));
201 assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
202 assert(port == (ipc_port_t) entry->ie_object);
203
204 *namep = name;
205 *entryp = entry;
206 return TRUE;
207 }
208
209 if (ipc_hash_lookup(space, (ipc_object_t) port, namep, entryp)) {
210 assert((entry = *entryp) != IE_NULL);
211 assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_SEND);
212 assert(port == (ipc_port_t) entry->ie_object);
213
214 return TRUE;
215 }
216
217 ip_unlock(port);
218 return FALSE;
219 }
220
221 /*
222 * Routine: ipc_right_dnrequest
223 * Purpose:
224 * Make a dead-name request, returning the previously
225 * registered send-once right. If notify is IP_NULL,
226 * just cancels the previously registered request.
227 *
228 * This interacts with the IE_BITS_COMPAT, because they
229 * both use ie_request. If this is a compat entry, then
230 * previous always gets IP_NULL. If notify is IP_NULL,
231 * then the entry remains a compat entry. Otherwise
232 * the real dead-name request is registered and the entry
233 * is no longer a compat entry.
234 * Conditions:
235 * Nothing locked. May allocate memory.
236 * Only consumes/returns refs if successful.
237 * Returns:
238 * KERN_SUCCESS Made/canceled dead-name request.
239 * KERN_INVALID_TASK The space is dead.
240 * KERN_INVALID_NAME Name doesn't exist in space.
241 * KERN_INVALID_RIGHT Name doesn't denote port/dead rights.
242 * KERN_INVALID_ARGUMENT Name denotes dead name, but
243 * immediate is FALSE or notify is IP_NULL.
244 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
245 */
246
247 kern_return_t
ipc_right_dnrequest(ipc_space_t space,mach_port_name_t name,boolean_t immediate,ipc_port_t notify,ipc_port_t * previousp)248 ipc_right_dnrequest(
249 ipc_space_t space,
250 mach_port_name_t name,
251 boolean_t immediate,
252 ipc_port_t notify,
253 ipc_port_t *previousp)
254 {
255 ipc_port_t previous;
256 ipc_port_t port = NULL;
257
258 for (;;) {
259 ipc_entry_t entry;
260 ipc_entry_bits_t bits;
261 kern_return_t kr;
262
263 kr = ipc_right_lookup_write(space, name, &entry);
264 ip_unlock_assert(port);
265 if (kr != KERN_SUCCESS)
266 return kr;
267 /* space is write-locked and active */
268
269 bits = entry->ie_bits;
270 if (bits & MACH_PORT_TYPE_PORT_RIGHTS) {
271
272 ipc_port_request_index_t request;
273
274 port = (ipc_port_t) entry->ie_object;
275 assert(port != IP_NULL);
276
277 if (!ipc_right_check(space, port, name, entry)) {
278 /* port is locked and active */
279
280 if (notify == IP_NULL) {
281 previous = ipc_right_dncancel_macro(
282 space, port, name, entry);
283
284 ip_unlock(port);
285 is_write_unlock(space);
286 break;
287 }
288
289 /*
290 * If a registered soright exists,
291 * want to atomically switch with it.
292 * If ipc_port_dncancel finds us a
293 * soright, then the following
294 * ipc_port_dnrequest will reuse
295 * that slot, so we are guaranteed
296 * not to unlock and retry.
297 */
298
299 previous = ipc_right_dncancel_macro(space,
300 port, name, entry);
301
302 kr = ipc_port_dnrequest(port, name, notify,
303 &request);
304 if (kr != KERN_SUCCESS) {
305 assert(previous == IP_NULL);
306 is_write_unlock(space);
307
308 kr = ipc_port_dngrow(port,
309 ITS_SIZE_NONE);
310 ip_unlock_assert(port);
311 /* port is unlocked */
312 if (kr != KERN_SUCCESS)
313 return kr;
314
315 continue;
316 }
317
318 assert(request != 0);
319 ip_unlock(port);
320
321 entry->ie_request = request;
322 is_write_unlock(space);
323 break;
324 }
325
326 bits = entry->ie_bits;
327 assert(bits & MACH_PORT_TYPE_DEAD_NAME);
328 }
329
330 if ((bits & MACH_PORT_TYPE_DEAD_NAME) &&
331 immediate && (notify != IP_NULL)) {
332
333 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
334 assert(ipc_entry_refs(entry) > 0);
335
336 ipc_entry_hold(entry); /* increment urefs */
337 is_write_unlock(space);
338
339 ipc_notify_dead_name(notify, name);
340 previous = IP_NULL;
341 break;
342 }
343
344 is_write_unlock(space);
345 if (port)
346 ip_unlock_assert(port);
347 if (bits & MACH_PORT_TYPE_PORT_OR_DEAD)
348 return KERN_INVALID_ARGUMENT;
349 else
350 return KERN_INVALID_RIGHT;
351 }
352 if (port)
353 ip_unlock_assert(port);
354 *previousp = previous;
355 return KERN_SUCCESS;
356 }
357
358 /*
359 * Routine: ipc_right_dncancel
360 * Purpose:
361 * Cancel a dead-name request and return the send-once right.
362 * Afterwards, entry->ie_request == 0.
363 * Conditions:
364 * The space must be write-locked; the port must be locked.
365 * The port must be active; the space doesn't have to be.
366 */
367
368 ipc_port_t
ipc_right_dncancel(ipc_space_t space,ipc_port_t port,mach_port_name_t name,ipc_entry_t entry)369 ipc_right_dncancel(
370 ipc_space_t space,
371 ipc_port_t port,
372 mach_port_name_t name,
373 ipc_entry_t entry)
374 {
375 ipc_port_t dnrequest;
376
377 assert(ip_active(port));
378 assert(port == (ipc_port_t) entry->ie_object);
379
380 dnrequest = ipc_port_dncancel(port, name, entry->ie_request);
381 entry->ie_request = 0;
382
383 return dnrequest;
384 }
385
386 /*
387 * Routine: ipc_right_inuse
388 * Purpose:
389 * Check if an entry is being used.
390 * Returns TRUE if it is.
391 * Conditions:
392 * The space is write-locked and active.
393 * It is unlocked if the entry is inuse.
394 */
395
396 boolean_t
ipc_right_inuse(ipc_space_t space,mach_port_name_t name,ipc_entry_t entry)397 ipc_right_inuse(
398 ipc_space_t space,
399 mach_port_name_t name,
400 ipc_entry_t entry)
401 {
402 ipc_entry_bits_t bits = entry->ie_bits;
403
404 if (IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE) {
405 is_write_unlock(space);
406 return TRUE;
407 }
408
409 return FALSE;
410 }
411
412 /*
413 * Routine: ipc_right_check
414 * Purpose:
415 * Check if the port has died. If it has,
416 * clean up the entry and return TRUE.
417 * Conditions:
418 * The space is write-locked; the port is not locked.
419 * If returns FALSE, the port is also locked and active.
420 * Otherwise, entry is converted to a dead name, freeing
421 * a reference to port.
422 *
423 */
424
425 boolean_t
ipc_right_check(ipc_space_t space,ipc_port_t port,mach_port_name_t name,ipc_entry_t entry)426 ipc_right_check(
427 ipc_space_t space,
428 ipc_port_t port,
429 mach_port_name_t name,
430 ipc_entry_t entry)
431 {
432 ipc_entry_bits_t bits;
433
434 assert(space->is_active);
435 assert(port == (ipc_port_t) entry->ie_object);
436
437 ip_lock(port);
438 if (ip_active(port)) {
439 return FALSE;
440 }
441 ip_unlock(port);
442
443 /* this was either a pure send right or a send-once right */
444
445 bits = entry->ie_bits;
446 assert((bits & MACH_PORT_TYPE_RECEIVE) == 0);
447 assert(ipc_entry_refs(entry) > 0);
448
449 if (bits & MACH_PORT_TYPE_SEND) {
450 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
451 ipc_hash_delete(space, (ipc_object_t) port, name, entry);
452 } else {
453 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
454 MACH_VERIFY(ipc_entry_refs(entry) == 1, ("urefs expected 1 got %d", ipc_entry_refs(entry)));
455 }
456
457 ipc_port_release(port);
458
459 /* convert entry to dead name */
460
461 bits = (bits &~ IE_BITS_TYPE_MASK) | MACH_PORT_TYPE_DEAD_NAME;
462
463 if (entry->ie_request != 0) {
464 entry->ie_request = 0;
465 ipc_entry_hold(entry); /* increment urefs */
466 }
467
468 entry->ie_bits = bits;
469 OBJECT_CLEAR(entry, name);
470 return TRUE;
471 }
472
473 /*
474 * Routine: ipc_right_clean
475 * Purpose:
476 * Cleans up an entry in a dead space.
477 * The entry isn't deallocated or removed
478 * from reverse hash tables.
479 * Conditions:
480 * The space is dead and unlocked.
481 */
482
483 void
ipc_right_clean(ipc_space_t space,mach_port_name_t name,ipc_entry_t entry)484 ipc_right_clean(
485 ipc_space_t space,
486 mach_port_name_t name,
487 ipc_entry_t entry)
488 {
489 ipc_entry_bits_t bits = entry->ie_bits;
490 mach_port_type_t type = IE_BITS_TYPE(bits);
491
492 assert(!space->is_active);
493
494 /*
495 * IE_BITS_COMPAT/ipc_right_dncancel doesn't have this
496 * problem, because we check that the port is active. If
497 * we didn't cancel IE_BITS_COMPAT, ipc_port_destroy
498 * would still work, but dead space refs would accumulate
499 * in ip_dnrequests. They would use up slots in
500 * ip_dnrequests and keep the spaces from being freed.
501 */
502
503 switch (type) {
504 case MACH_PORT_TYPE_DEAD_NAME:
505 assert(entry->ie_request == 0);
506 assert(entry->ie_object == IO_NULL);
507 break;
508
509 case MACH_PORT_TYPE_PORT_SET: {
510 ipc_pset_t pset = (ipc_pset_t) entry->ie_object;
511
512 assert(entry->ie_request == 0);
513 assert(pset != IPS_NULL);
514 assert(ips_active(pset));
515
516 sx_slock(&pset->ips_note_lock);
517 KNOTE(&pset->ips_note, EV_EOF, KNF_LISTLOCKED);
518 sx_sunlock(&pset->ips_note_lock);
519 ipc_entry_close(space, name);
520 break;
521 }
522
523 case MACH_PORT_TYPE_SEND:
524 case MACH_PORT_TYPE_RECEIVE:
525 case MACH_PORT_TYPE_SEND_RECEIVE:
526 case MACH_PORT_TYPE_SEND_ONCE: {
527 ipc_port_t port = (ipc_port_t) entry->ie_object;
528 ipc_port_t dnrequest;
529 ipc_port_t nsrequest = IP_NULL;
530 mach_port_mscount_t mscount;
531
532 assert(port != IP_NULL);
533 ip_lock(port);
534
535 if (!ip_active(port)) {
536 ip_unlock(port);
537 ip_release(port);
538 break;
539 }
540
541 dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
542
543 if (type & MACH_PORT_TYPE_SEND) {
544 assert(port->ip_srights > 0);
545 if (--port->ip_srights == 0
546 ) {
547 nsrequest = port->ip_nsrequest;
548 if (nsrequest != IP_NULL) {
549 port->ip_nsrequest = IP_NULL;
550 mscount = port->ip_mscount;
551 }
552 }
553 }
554
555 if (type & MACH_PORT_TYPE_RECEIVE) {
556 assert(port->ip_receiver_name == name);
557 assert(port->ip_receiver == space);
558
559 ipc_port_clear_receiver(port);
560 ipc_port_destroy(port); /* consumes our ref, unlocks */
561 } else if (type & MACH_PORT_TYPE_SEND_ONCE) {
562 assert(port->ip_sorights > 0);
563 ip_unlock(port);
564
565 ipc_notify_send_once(port); /* consumes our ref */
566 } else {
567 assert(port->ip_receiver != space);
568
569 ip_unlock(port); /* port is active */
570 ip_release(port);
571 }
572
573 if (nsrequest != IP_NULL)
574 ipc_notify_no_senders(nsrequest, mscount);
575
576 if (dnrequest != IP_NULL)
577 ipc_notify_port_deleted(dnrequest, name);
578 break;
579 }
580
581 default:
582 panic("ipc_right_clean: strange type");
583 }
584 }
585
586 /*
587 * Routine: ipc_right_destroy
588 * Purpose:
589 * Destroys an entry in a space.
590 * Conditions:
591 * The space is write-locked, and is unlocked upon return.
592 * The space must be active.
593 * Returns:
594 * KERN_SUCCESS The entry was destroyed.
595 */
596
597 kern_return_t
ipc_right_destroy(ipc_space_t space,mach_port_name_t name,ipc_entry_t entry)598 ipc_right_destroy(
599 ipc_space_t space,
600 mach_port_name_t name,
601 ipc_entry_t entry)
602 {
603 ipc_entry_bits_t bits = entry->ie_bits;
604 mach_port_type_t type = IE_BITS_TYPE(bits);
605
606 assert(space->is_active);
607
608 switch (type) {
609 case MACH_PORT_TYPE_DEAD_NAME:
610 assert(entry->ie_request == 0);
611 assert(entry->ie_object == IO_NULL);
612
613 ipc_entry_dealloc(space, name, entry);
614 is_write_unlock(space);
615 break;
616
617 case MACH_PORT_TYPE_PORT_SET: {
618 ipc_pset_t pset = (ipc_pset_t) entry->ie_object;
619
620 assert(entry->ie_request == 0);
621 assert(pset != IPS_NULL);
622
623
624 is_write_unlock(space);
625
626 assert(ips_active(pset));
627 sx_slock(&pset->ips_note_lock);
628 KNOTE(&pset->ips_note, EV_EOF, KNF_LISTLOCKED);
629 sx_sunlock(&pset->ips_note_lock);
630 ipc_entry_close(space, name);
631
632 break;
633 }
634
635 case MACH_PORT_TYPE_SEND:
636 case MACH_PORT_TYPE_RECEIVE:
637 case MACH_PORT_TYPE_SEND_RECEIVE:
638 case MACH_PORT_TYPE_SEND_ONCE: {
639 ipc_port_t port = (ipc_port_t) entry->ie_object;
640 ipc_port_t nsrequest = IP_NULL;
641 mach_port_mscount_t mscount;
642 ipc_port_t dnrequest;
643
644 assert(port != IP_NULL);
645
646 if (type == MACH_PORT_TYPE_SEND)
647 ipc_hash_delete(space, (ipc_object_t) port,
648 name, entry);
649
650 ip_lock(port);
651
652 if (!ip_active(port)) {
653 assert((type & MACH_PORT_TYPE_RECEIVE) == 0);
654 ip_unlock(port);
655 ip_release(port);
656
657 entry->ie_request = 0;
658 OBJECT_CLEAR(entry, name);
659 ipc_entry_dealloc(space, name, entry);
660 is_write_unlock(space);
661 break;
662 }
663
664 dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
665
666 OBJECT_CLEAR(entry, name);
667 ipc_entry_dealloc(space, name, entry);
668 is_write_unlock(space);
669
670 if (type & MACH_PORT_TYPE_SEND) {
671 assert(port->ip_srights > 0);
672 if (--port->ip_srights == 0
673 ) {
674 nsrequest = port->ip_nsrequest;
675 if (nsrequest != IP_NULL) {
676 port->ip_nsrequest = IP_NULL;
677 mscount = port->ip_mscount;
678 }
679 }
680 }
681
682 if (type & MACH_PORT_TYPE_RECEIVE) {
683 assert(ip_active(port));
684 assert(port->ip_receiver == space);
685
686 ipc_port_clear_receiver(port);
687 ipc_port_destroy(port); /* consumes our ref, unlocks */
688 } else if (type & MACH_PORT_TYPE_SEND_ONCE) {
689 assert(port->ip_sorights > 0);
690 ip_unlock(port);
691
692 ipc_notify_send_once(port); /* consumes our ref */
693 } else {
694 assert(port->ip_receiver != space);
695
696 ip_unlock(port);
697 ip_release(port);
698 }
699
700 if (nsrequest != IP_NULL)
701 ipc_notify_no_senders(nsrequest, mscount);
702
703 if (dnrequest != IP_NULL)
704 ipc_notify_port_deleted(dnrequest, name);
705 break;
706 }
707
708 default:
709 panic("ipc_right_destroy: strange type");
710 }
711
712 return KERN_SUCCESS;
713 }
714
715 /*
716 * Routine: ipc_right_dealloc
717 * Purpose:
718 * Releases a send/send-once/dead-name user ref.
719 * Like ipc_right_delta with a delta of -1,
720 * but looks at the entry to determine the right.
721 * Conditions:
722 * The space is write-locked, and is unlocked upon return.
723 * The space must be active.
724 * Returns:
725 * KERN_SUCCESS A user ref was released.
726 * KERN_INVALID_RIGHT Entry has wrong type.
727 */
728
729 kern_return_t
ipc_right_dealloc(ipc_space_t space,mach_port_name_t name,ipc_entry_t entry)730 ipc_right_dealloc(
731 ipc_space_t space,
732 mach_port_name_t name,
733 ipc_entry_t entry)
734 {
735 ipc_entry_bits_t bits = entry->ie_bits;
736 mach_port_type_t type = IE_BITS_TYPE(bits);
737
738 assert(space->is_active);
739
740 switch (type) {
741 case MACH_PORT_TYPE_DEAD_NAME: {
742 dead_name:
743
744 assert(ipc_entry_refs(entry) > 0);
745 assert(entry->ie_request == 0);
746 assert(entry->ie_object == IO_NULL);
747
748 if (ipc_entry_refs(entry) > 1) {
749 ipc_entry_release(entry);
750 is_write_unlock(space);
751 } else
752 ipc_entry_dealloc(space, name, entry);
753
754 break;
755 }
756
757 case MACH_PORT_TYPE_SEND_ONCE: {
758 ipc_port_t port, dnrequest;
759
760 MACH_VERIFY(ipc_entry_refs(entry) == 1, ("urefs expected 1 got %d", ipc_entry_refs(entry)));
761 port = (ipc_port_t) entry->ie_object;
762 assert(port != IP_NULL);
763
764 if (ipc_right_check(space, port, name, entry)) {
765
766 bits = entry->ie_bits;
767 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
768 goto dead_name;
769 }
770 /* port is locked and active */
771
772 assert(port->ip_sorights > 0);
773
774 dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
775 ip_unlock(port);
776
777 OBJECT_CLEAR(entry, name);
778 /* drops the lock */
779 ipc_entry_dealloc(space, name, entry);
780
781 ipc_notify_send_once(port);
782
783 if (dnrequest != IP_NULL)
784 ipc_notify_port_deleted(dnrequest, name);
785 break;
786 }
787
788 case MACH_PORT_TYPE_SEND: {
789 ipc_port_t port;
790 ipc_port_t dnrequest = IP_NULL;
791 ipc_port_t nsrequest = IP_NULL;
792 mach_port_mscount_t mscount;
793
794
795 assert(ipc_entry_refs(entry) > 0);
796
797 port = (ipc_port_t) entry->ie_object;
798 assert(port != IP_NULL);
799
800 if (ipc_right_check(space, port, name, entry)) {
801 bits = entry->ie_bits;
802 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
803 goto dead_name;
804 }
805 /* port is locked and active */
806
807 assert(port->ip_srights > 0);
808
809 if (ipc_entry_refs(entry) > 1) {
810 ip_unlock(port);
811 ipc_entry_release(entry); /* decrement urefs */
812 is_write_unlock(space);
813 } else {
814 if (--port->ip_srights == 0
815 ) {
816 nsrequest = port->ip_nsrequest;
817 if (nsrequest != IP_NULL) {
818 port->ip_nsrequest = IP_NULL;
819 mscount = port->ip_mscount;
820 }
821
822 }
823
824 dnrequest = ipc_right_dncancel_macro(space, port,
825 name, entry);
826
827 ipc_hash_delete(space, (ipc_object_t) port,
828 name, entry);
829 ip_unlock(port);
830 ip_release(port);
831 OBJECT_CLEAR(entry, name);
832 /* drops the space lock */
833 ipc_entry_dealloc(space, name, entry);
834 }
835 /* even if dropped a ref, port is active */
836
837
838 if (nsrequest != IP_NULL)
839 ipc_notify_no_senders(nsrequest, mscount);
840
841 if (dnrequest != IP_NULL)
842 ipc_notify_port_deleted(dnrequest, name);
843 break;
844 }
845
846 case MACH_PORT_TYPE_SEND_RECEIVE: {
847 ipc_port_t port;
848 ipc_port_t nsrequest = IP_NULL;
849 mach_port_mscount_t mscount;
850
851 assert(ipc_entry_refs(entry) > 0);
852
853 port = (ipc_port_t) entry->ie_object;
854 assert(port != IP_NULL);
855
856 ip_lock(port);
857 assert(ip_active(port));
858 assert(port->ip_receiver_name == name);
859 assert(port->ip_receiver == space);
860 assert(port->ip_srights > 0);
861
862 if (ipc_entry_refs(entry) > 1) {
863 ipc_entry_release(entry);
864 } else {
865 if (--port->ip_srights == 0
866 ) {
867 nsrequest = port->ip_nsrequest;
868 if (nsrequest != IP_NULL) {
869 port->ip_nsrequest = IP_NULL;
870 mscount = port->ip_mscount;
871 }
872 }
873
874 entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK|
875 MACH_PORT_TYPE_SEND);
876 }
877
878 ip_unlock(port);
879 is_write_unlock(space);
880
881 if (nsrequest != IP_NULL)
882 ipc_notify_no_senders(nsrequest, mscount);
883 break;
884 }
885
886 default:
887 is_write_unlock(space);
888 return KERN_INVALID_RIGHT;
889 }
890
891 return KERN_SUCCESS;
892 }
893
894 /*
895 * Routine: ipc_right_delta
896 * Purpose:
897 * Modifies the user-reference count for a right.
898 * May deallocate the right, if the count goes to zero.
899 * Conditions:
900 * The space is write-locked, and is unlocked upon return.
901 * The space must be active.
902 * Returns:
903 * KERN_SUCCESS Count was modified.
904 * KERN_INVALID_RIGHT Entry has wrong type.
905 * KERN_INVALID_VALUE Bad delta for the right.
906 */
907
908 kern_return_t
ipc_right_delta(ipc_space_t space,mach_port_name_t name,ipc_entry_t entry,mach_port_right_t right,mach_port_delta_t delta)909 ipc_right_delta(
910 ipc_space_t space,
911 mach_port_name_t name,
912 ipc_entry_t entry,
913 mach_port_right_t right,
914 mach_port_delta_t delta)
915 {
916 ipc_entry_bits_t bits = entry->ie_bits;
917
918 /*
919 * The following is used (for case MACH_PORT_RIGHT_DEAD_NAME) in the
920 * switch below. It is used to keep track of those cases (in DIPC)
921 * where we have postponed the dropping of a port reference. Since
922 * the dropping of the reference could cause the port to disappear
923 * we postpone doing so when we are holding the space lock.
924 */
925
926
927 assert(space->is_active);
928 assert(right < MACH_PORT_RIGHT_NUMBER);
929
930 /* Rights-specific restrictions and operations. */
931
932 switch (right) {
933 case MACH_PORT_RIGHT_PORT_SET: {
934 ipc_pset_t pset;
935
936 if ((bits & MACH_PORT_TYPE_PORT_SET) == 0)
937 goto invalid_right;
938
939 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_PORT_SET);
940 assert(IE_BITS_UREFS(bits) == 0);
941 assert(entry->ie_request == 0);
942
943 if (delta == 0)
944 goto success;
945
946 if (delta != -1)
947 goto invalid_value;
948
949 pset = (ipc_pset_t) entry->ie_object;
950 assert(pset != IPS_NULL);
951 assert(ips_active(pset));
952
953 /* space must be unlocked when calling KNOTE & close */
954 is_write_unlock(space);
955
956 sx_slock(&pset->ips_note_lock);
957 KNOTE(&pset->ips_note, EV_EOF, KNF_LISTLOCKED);
958 sx_sunlock(&pset->ips_note_lock);
959
960 ipc_entry_close(space, name);
961
962 break;
963 }
964
965 case MACH_PORT_RIGHT_RECEIVE: {
966 ipc_port_t port;
967 ipc_port_t dnrequest = IP_NULL;
968
969 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
970 goto invalid_right;
971
972 if (delta == 0)
973 goto success;
974
975 if (delta != -1)
976 goto invalid_value;
977
978 port = (ipc_port_t) entry->ie_object;
979 assert(port != IP_NULL);
980
981 /*
982 * The port lock is needed for ipc_right_dncancel;
983 * otherwise, we wouldn't have to take the lock
984 * until just before dropping the space lock.
985 */
986
987 ip_lock(port);
988 assert(ip_active(port));
989 assert(port->ip_receiver_name == name);
990 assert(port->ip_receiver == space);
991
992 if (bits & MACH_PORT_TYPE_SEND) {
993 assert(IE_BITS_TYPE(bits) ==
994 MACH_PORT_TYPE_SEND_RECEIVE);
995 assert(ipc_entry_refs(entry) > 0);
996 assert(port->ip_srights > 0);
997
998 /*
999 * The remaining send right turns into a
1000 * dead name. Notice we don't decrement
1001 * ip_srights, generate a no-senders notif,
1002 * or use ipc_right_dncancel, because the
1003 * port is destroyed "first".
1004 */
1005
1006 bits &= ~IE_BITS_TYPE_MASK;
1007 bits |= MACH_PORT_TYPE_DEAD_NAME;
1008
1009 if (entry->ie_request != 0) {
1010 entry->ie_request = 0;
1011 ipc_entry_hold(entry); /* increment urefs */
1012 }
1013
1014 entry->ie_bits = bits;
1015 OBJECT_CLEAR(entry, name);
1016 is_write_unlock(space);
1017 } else {
1018 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
1019
1020 dnrequest = ipc_right_dncancel_macro(space, port,
1021 name, entry);
1022 OBJECT_CLEAR(entry, name);
1023 /* drops the space lock */
1024 ipc_entry_dealloc(space, name, entry);
1025 }
1026
1027
1028 ipc_port_clear_receiver(port);
1029 ipc_port_destroy(port); /* consumes ref, unlocks */
1030
1031 if (dnrequest != IP_NULL)
1032 ipc_notify_port_deleted(dnrequest, name);
1033 break;
1034 }
1035
1036 case MACH_PORT_RIGHT_SEND_ONCE: {
1037 ipc_port_t port, dnrequest;
1038
1039 if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0)
1040 goto invalid_right;
1041
1042 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1043 MACH_VERIFY(ipc_entry_refs(entry) == 1, ("urefs expected 1 got %d", ipc_entry_refs(entry)));
1044
1045 port = (ipc_port_t) entry->ie_object;
1046 assert(port != IP_NULL);
1047
1048 if (ipc_right_check(space, port, name, entry)) {
1049 assert(!(entry->ie_bits & MACH_PORT_TYPE_SEND_ONCE));
1050 goto invalid_right;
1051 }
1052 /* port is locked and active */
1053
1054 assert(port->ip_sorights > 0);
1055
1056 if ((delta > 0) || (delta < -1)) {
1057 ip_unlock(port);
1058 goto invalid_value;
1059 }
1060
1061 if (delta == 0) {
1062 ip_unlock(port);
1063 goto success;
1064 }
1065
1066 dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
1067 ip_unlock(port);
1068
1069 OBJECT_CLEAR(entry, name);
1070 /* drops the space lock */
1071 ipc_entry_dealloc(space, name, entry);
1072
1073 ipc_notify_send_once(port);
1074
1075 if (dnrequest != IP_NULL)
1076 ipc_notify_port_deleted(dnrequest, name);
1077 break;
1078 }
1079
1080 case MACH_PORT_RIGHT_DEAD_NAME: {
1081 mach_port_urefs_t urefs;
1082
1083 if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
1084 ipc_port_t port;
1085
1086 port = (ipc_port_t) entry->ie_object;
1087 assert(port != IP_NULL);
1088 if (!ipc_right_check(space, port, name, entry)) {
1089 /* port is locked and active */
1090 ip_unlock(port);
1091 goto invalid_right;
1092 }
1093 bits = entry->ie_bits;
1094 } else if ((bits & MACH_PORT_TYPE_DEAD_NAME) == 0)
1095 goto invalid_right;
1096
1097 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
1098 assert(ipc_entry_refs(entry) > 0);
1099 assert(entry->ie_object == IO_NULL);
1100 assert(entry->ie_request == 0);
1101
1102 urefs = ipc_entry_refs(entry);
1103 if (MACH_PORT_UREFS_UNDERFLOW(urefs, delta))
1104 goto invalid_value;
1105
1106 if ((urefs + delta) == 0) {
1107 /* drops the space lock */
1108 ipc_entry_dealloc(space, name, entry);
1109 } else {
1110 ipc_entry_add_refs(entry, delta);
1111 is_write_unlock(space);
1112 }
1113 break;
1114 }
1115
1116 case MACH_PORT_RIGHT_SEND: {
1117 mach_port_urefs_t urefs;
1118 ipc_port_t port;
1119 ipc_port_t dnrequest = IP_NULL;
1120 ipc_port_t nsrequest = IP_NULL;
1121 mach_port_mscount_t mscount;
1122
1123 if ((bits & MACH_PORT_TYPE_SEND) == 0)
1124 goto invalid_right;
1125
1126 /* maximum urefs for send is MACH_PORT_UREFS_MAX-1 */
1127
1128 port = (ipc_port_t) entry->ie_object;
1129 assert(port != IP_NULL);
1130
1131 if (ipc_right_check(space, port, name, entry)) {
1132 assert((entry->ie_bits & MACH_PORT_TYPE_SEND) == 0);
1133 goto invalid_right;
1134 }
1135 /* port is locked and active */
1136
1137 assert(port->ip_srights > 0);
1138
1139 urefs = ipc_entry_refs(entry);
1140 if (MACH_PORT_UREFS_UNDERFLOW(urefs, delta)) {
1141 ip_unlock(port);
1142 goto invalid_value;
1143 }
1144
1145 if ((urefs + delta) == 0) {
1146 if (--port->ip_srights == 0
1147 ) {
1148 nsrequest = port->ip_nsrequest;
1149 if (nsrequest != IP_NULL) {
1150 port->ip_nsrequest = IP_NULL;
1151 mscount = port->ip_mscount;
1152 }
1153 }
1154
1155 if (bits & MACH_PORT_TYPE_RECEIVE) {
1156 assert(port->ip_receiver_name == name);
1157 assert(port->ip_receiver == space);
1158 assert(IE_BITS_TYPE(bits) ==
1159 MACH_PORT_TYPE_SEND_RECEIVE);
1160
1161 entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK|
1162 MACH_PORT_TYPE_SEND);
1163 ip_unlock(port);
1164 is_write_unlock(space);
1165
1166 } else {
1167 assert(IE_BITS_TYPE(bits) ==
1168 MACH_PORT_TYPE_SEND);
1169
1170 dnrequest = ipc_right_dncancel_macro(
1171 space, port, name, entry);
1172
1173 ipc_hash_delete(space, (ipc_object_t) port,
1174 name, entry);
1175 ip_unlock(port);
1176 ip_release(port);
1177 OBJECT_CLEAR(entry, name);
1178 /* drops the space lock */
1179 ipc_entry_dealloc(space, name, entry);
1180 }
1181 } else {
1182 is_write_unlock(space);
1183 ip_unlock(port);
1184 ipc_entry_add_refs(entry, delta);
1185 }
1186 /* even if dropped a ref, port is active */
1187
1188
1189 if (nsrequest != IP_NULL)
1190 ipc_notify_no_senders(nsrequest, mscount);
1191
1192 if (dnrequest != IP_NULL)
1193 ipc_notify_port_deleted(dnrequest, name);
1194 break;
1195 }
1196
1197 default:
1198 panic("ipc_right_delta: strange right");
1199 }
1200
1201 return KERN_SUCCESS;
1202
1203 success:
1204 is_write_unlock(space);
1205 return KERN_SUCCESS;
1206
1207 invalid_right:
1208 is_write_unlock(space);
1209 return KERN_INVALID_RIGHT;
1210
1211 invalid_value:
1212 is_write_unlock(space);
1213 return KERN_INVALID_VALUE;
1214 }
1215
1216 /*
1217 * Routine: ipc_right_info
1218 * Purpose:
1219 * Retrieves information about the right.
1220 * Conditions:
1221 * The space is write-locked, and is unlocked upon return
1222 * if the call is unsuccessful. The space must be active.
1223 * Returns:
1224 * KERN_SUCCESS Retrieved info; space still locked.
1225 */
1226
1227 kern_return_t
ipc_right_info(ipc_space_t space,mach_port_name_t name,ipc_entry_t entry,mach_port_type_t * typep,mach_port_urefs_t * urefsp)1228 ipc_right_info(
1229 ipc_space_t space,
1230 mach_port_name_t name,
1231 ipc_entry_t entry,
1232 mach_port_type_t *typep,
1233 mach_port_urefs_t *urefsp)
1234 {
1235 ipc_entry_bits_t bits = entry->ie_bits;
1236 ipc_port_request_index_t request;
1237 mach_port_type_t type;
1238
1239 if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
1240 ipc_port_t port = (ipc_port_t) entry->ie_object;
1241
1242 if (ipc_right_check(space, port, name, entry)) {
1243 bits = entry->ie_bits;
1244 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
1245 } else
1246 ip_unlock(port);
1247 }
1248
1249 type = IE_BITS_TYPE(bits);
1250 request = entry->ie_request;
1251
1252 if (request != 0)
1253 type |= MACH_PORT_TYPE_DNREQUEST;
1254
1255 *typep = type;
1256 *urefsp = ipc_entry_refs(entry);
1257 return KERN_SUCCESS;
1258 }
1259
1260 /*
1261 * Routine: ipc_right_copyin_check
1262 * Purpose:
1263 * Check if a subsequent ipc_right_copyin (for receiver) would succeed.
1264 * Conditions:
1265 * The space is locked (read or write) and active.
1266 */
1267
1268 boolean_t
ipc_right_copyin_check(ipc_space_t space,mach_port_name_t name,ipc_entry_t entry,mach_msg_type_name_t msgt_name)1269 ipc_right_copyin_check(
1270 ipc_space_t space,
1271 mach_port_name_t name,
1272 ipc_entry_t entry,
1273 mach_msg_type_name_t msgt_name)
1274 {
1275 ipc_port_t port = (ipc_port_t) entry->ie_object;
1276 ipc_entry_bits_t bits = entry->ie_bits;
1277
1278 assert(space->is_active);
1279
1280 switch (msgt_name) {
1281 case MACH_MSG_TYPE_MAKE_SEND:
1282 case MACH_MSG_TYPE_MAKE_SEND_ONCE:
1283 case MACH_MSG_TYPE_MOVE_RECEIVE:
1284 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1285 return FALSE;
1286 if (port == NULL)
1287 return (FALSE);
1288 if (port->ip_receiver != space)
1289 return (FALSE);
1290 break;
1291
1292 case MACH_MSG_TYPE_COPY_SEND:
1293 case MACH_MSG_TYPE_MOVE_SEND:
1294 case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
1295 boolean_t active;
1296
1297 if (bits & MACH_PORT_TYPE_DEAD_NAME)
1298 break;
1299
1300 if (port == NULL)
1301 return (FALSE);
1302 if (port->ip_receiver != space)
1303 return (FALSE);
1304
1305 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
1306 return FALSE;
1307
1308 ip_lock(port);
1309 active = ip_active(port);
1310 ip_unlock(port);
1311
1312 if (!active) {
1313 break;
1314 }
1315
1316 if (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE) {
1317 if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0)
1318 return FALSE;
1319 } else {
1320 if ((bits & MACH_PORT_TYPE_SEND) == 0)
1321 return FALSE;
1322 }
1323
1324 break;
1325 }
1326
1327 default:
1328 panic("ipc_right_copyin_check: strange rights");
1329 }
1330
1331 return TRUE;
1332 }
1333
1334 /*
1335 * Routine: ipc_right_copyin
1336 * Purpose:
1337 * Copyin a capability from a space.
1338 * If successful, the caller gets a ref
1339 * for the resulting object, unless it is IO_DEAD,
1340 * and possibly a send-once right which should
1341 * be used in a port-deleted notification.
1342 *
1343 * If deadok is not TRUE, the copyin operation
1344 * will fail instead of producing IO_DEAD.
1345 *
1346 * The entry is never deallocated (except
1347 * when KERN_INVALID_NAME), so the caller
1348 * should deallocate the entry if its type
1349 * is MACH_PORT_TYPE_NONE.
1350 * Conditions:
1351 * The space is write-locked and active.
1352 * Returns:
1353 * KERN_SUCCESS Acquired an object, possibly IO_DEAD.
1354 * KERN_INVALID_RIGHT Name doesn't denote correct right.
1355 */
1356
1357 #define ELOG printf("%s:%d bits: %08x\n", __FILE__, __LINE__, bits)
1358
1359 kern_return_t
ipc_right_copyin(ipc_space_t space,mach_port_name_t name,ipc_entry_t entry,mach_msg_type_name_t msgt_name,boolean_t deadok,ipc_object_t * objectp,ipc_port_t * sorightp)1360 ipc_right_copyin(
1361 ipc_space_t space,
1362 mach_port_name_t name,
1363 ipc_entry_t entry,
1364 mach_msg_type_name_t msgt_name,
1365 boolean_t deadok,
1366 ipc_object_t *objectp,
1367 ipc_port_t *sorightp)
1368 {
1369 ipc_entry_bits_t bits = entry->ie_bits;
1370
1371 assert(space->is_active);
1372
1373 switch (msgt_name) {
1374 case MACH_MSG_TYPE_MAKE_SEND: {
1375 ipc_port_t port;
1376
1377 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) {
1378 ELOG;
1379 goto invalid_right;
1380 }
1381 port = (ipc_port_t) entry->ie_object;
1382 assert(port != IP_NULL);
1383
1384 ip_lock(port);
1385 assert(ip_active(port));
1386 assert(port->ip_receiver_name == name);
1387 assert(port->ip_receiver == space);
1388
1389 port->ip_mscount++;
1390 port->ip_srights++;
1391 ip_reference(port);
1392 ip_unlock(port);
1393
1394 *objectp = (ipc_object_t) port;
1395 *sorightp = IP_NULL;
1396 break;
1397 }
1398
1399 case MACH_MSG_TYPE_MAKE_SEND_ONCE: {
1400 ipc_port_t port;
1401
1402 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) {
1403 ELOG;
1404 goto invalid_right;
1405 }
1406 port = (ipc_port_t) entry->ie_object;
1407 assert(port != IP_NULL);
1408
1409 ip_lock(port);
1410 assert(ip_active(port));
1411 assert(port->ip_receiver_name == name);
1412 assert(port->ip_receiver == space);
1413
1414 port->ip_sorights++;
1415 ip_reference(port);
1416 ip_unlock(port);
1417
1418 *objectp = (ipc_object_t) port;
1419 *sorightp = IP_NULL;
1420 break;
1421 }
1422
1423 case MACH_MSG_TYPE_MOVE_RECEIVE: {
1424 ipc_port_t port;
1425 ipc_port_t dnrequest = IP_NULL;
1426
1427 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) {
1428 ELOG;
1429 goto invalid_right;
1430 }
1431 port = (ipc_port_t) entry->ie_object;
1432 assert(port != IP_NULL);
1433
1434 ip_lock(port);
1435 assert(ip_active(port));
1436 assert(port->ip_receiver_name == name);
1437 assert(port->ip_receiver == space);
1438
1439 if (bits & MACH_PORT_TYPE_SEND) {
1440 assert(IE_BITS_TYPE(bits) ==
1441 MACH_PORT_TYPE_SEND_RECEIVE);
1442 assert(ipc_entry_refs(entry) > 0);
1443 assert(port->ip_srights > 0);
1444
1445 ipc_hash_insert(space, (ipc_object_t) port,
1446 name, entry);
1447
1448 ip_reference(port);
1449 } else {
1450 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
1451 assert(IE_BITS_UREFS(bits) == 0);
1452
1453 dnrequest = ipc_right_dncancel_macro(space, port,
1454 name, entry);
1455
1456 OBJECT_CLEAR(entry, name);
1457 }
1458 entry->ie_bits = bits &~ MACH_PORT_TYPE_RECEIVE;
1459
1460 ipc_port_clear_receiver(port);
1461
1462 port->ip_receiver_name = MACH_PORT_NAME_NULL;
1463 port->ip_destination = IP_NULL;
1464 ip_unlock(port);
1465
1466 *objectp = (ipc_object_t) port;
1467 *sorightp = dnrequest;
1468 break;
1469 }
1470
1471 case MACH_MSG_TYPE_COPY_SEND: {
1472 ipc_port_t port;
1473
1474 if (bits & MACH_PORT_TYPE_DEAD_NAME)
1475 goto copy_dead;
1476
1477 /* allow for dead send-once rights */
1478
1479 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0) {
1480 goto invalid_right;
1481 }
1482 assert(ipc_entry_refs(entry) > 0);
1483
1484 port = (ipc_port_t) entry->ie_object;
1485 assert(port != IP_NULL);
1486
1487 if (ipc_right_check(space, port, name, entry)) {
1488 bits = entry->ie_bits;
1489 goto copy_dead;
1490 }
1491 /* port is locked and active */
1492
1493 if ((bits & MACH_PORT_TYPE_SEND) == 0) {
1494 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1495 assert(port->ip_sorights > 0);
1496
1497 ip_unlock(port);
1498 ELOG;
1499 goto invalid_right;
1500 }
1501
1502 assert(port->ip_srights > 0);
1503
1504 port->ip_srights++;
1505 ip_reference(port);
1506 ip_unlock(port);
1507
1508 *objectp = (ipc_object_t) port;
1509 *sorightp = IP_NULL;
1510 break;
1511 }
1512
1513 case MACH_MSG_TYPE_MOVE_SEND: {
1514 ipc_port_t port;
1515 ipc_port_t dnrequest = IP_NULL;
1516
1517 if (bits & MACH_PORT_TYPE_DEAD_NAME)
1518 goto move_dead;
1519
1520 /* allow for dead send-once rights */
1521
1522 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0) {
1523 ELOG;
1524 goto invalid_right;
1525 }
1526 assert(ipc_entry_refs(entry) > 0);
1527
1528 port = (ipc_port_t) entry->ie_object;
1529 assert(port != IP_NULL);
1530
1531 if (ipc_right_check(space, port, name, entry)) {
1532 bits = entry->ie_bits;
1533 goto move_dead;
1534 }
1535 /* port is locked and active */
1536
1537 if ((bits & MACH_PORT_TYPE_SEND) == 0) {
1538 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1539 assert(port->ip_sorights > 0);
1540
1541 ip_unlock(port);
1542 ELOG;
1543 goto invalid_right;
1544 }
1545
1546 assert(port->ip_srights > 0);
1547
1548 if (ipc_entry_refs(entry) == 1) {
1549 if (bits & MACH_PORT_TYPE_RECEIVE) {
1550 assert(port->ip_receiver_name == name);
1551 assert(port->ip_receiver == space);
1552 assert(IE_BITS_TYPE(bits) ==
1553 MACH_PORT_TYPE_SEND_RECEIVE);
1554
1555 ip_reference(port);
1556 } else {
1557 assert(IE_BITS_TYPE(bits) ==
1558 MACH_PORT_TYPE_SEND);
1559
1560 dnrequest = ipc_right_dncancel_macro(
1561 space, port, name, entry);
1562
1563 ipc_hash_delete(space, (ipc_object_t) port,
1564 name, entry);
1565 OBJECT_CLEAR(entry, name);
1566 }
1567 entry->ie_bits = bits &~
1568 (IE_BITS_UREFS_MASK|MACH_PORT_TYPE_SEND);
1569 } else {
1570 MPASS(ipc_entry_refs(entry) > 1);
1571 port->ip_srights++;
1572 ip_reference(port);
1573 ipc_entry_release(entry); /* decrement urefs */
1574 }
1575
1576 ip_unlock(port);
1577
1578 *objectp = (ipc_object_t) port;
1579 *sorightp = dnrequest;
1580 break;
1581 }
1582
1583 case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
1584 ipc_port_t port;
1585 ipc_port_t dnrequest;
1586
1587 if (bits & MACH_PORT_TYPE_DEAD_NAME)
1588 goto move_dead;
1589
1590 /* allow for dead send rights */
1591
1592 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0) {
1593 ELOG;
1594 goto invalid_right;
1595 }
1596 assert(ipc_entry_refs(entry) > 0);
1597
1598 port = (ipc_port_t) entry->ie_object;
1599 assert(port != IP_NULL);
1600
1601 if (ipc_right_check(space, port, name, entry)) {
1602 bits = entry->ie_bits;
1603 ELOG;
1604 goto move_dead;
1605 }
1606 /* port is locked and active */
1607
1608 if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0) {
1609 assert(bits & MACH_PORT_TYPE_SEND);
1610 assert(port->ip_srights > 0);
1611
1612 ip_unlock(port);
1613 ELOG;
1614 goto invalid_right;
1615 }
1616
1617 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1618 MACH_VERIFY(ipc_entry_refs(entry) == 1, ("urefs expected 1 got %d", ipc_entry_refs(entry)));
1619 assert(port->ip_sorights > 0);
1620
1621 dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
1622 ip_unlock(port);
1623
1624 OBJECT_CLEAR(entry, name);
1625 entry->ie_bits = bits &~ MACH_PORT_TYPE_SEND_ONCE;
1626
1627 *objectp = (ipc_object_t) port;
1628 *sorightp = dnrequest;
1629 break;
1630 }
1631
1632 default:
1633 panic("ipc_right_copyin: strange rights");
1634 }
1635
1636 return KERN_SUCCESS;
1637
1638 copy_dead:
1639 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
1640 assert(ipc_entry_refs(entry) > 0);
1641 assert(entry->ie_request == 0);
1642 assert(entry->ie_object == 0);
1643
1644 if (!deadok) {
1645 ELOG;
1646 goto invalid_right;
1647 }
1648 *objectp = IO_DEAD;
1649 *sorightp = IP_NULL;
1650 return KERN_SUCCESS;
1651
1652 move_dead:
1653 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
1654 assert(ipc_entry_refs(entry) > 0);
1655 assert(entry->ie_request == 0);
1656 assert(entry->ie_object == 0);
1657
1658 if (!deadok) {
1659 ELOG;
1660 goto invalid_right;
1661 }
1662 if (ipc_entry_refs(entry) > 1)
1663 ipc_entry_release(entry); /* decrement urefs */
1664 else
1665 entry->ie_bits = bits &~ MACH_PORT_TYPE_DEAD_NAME;
1666
1667 *objectp = IO_DEAD;
1668 *sorightp = IP_NULL;
1669 return KERN_SUCCESS;
1670
1671 invalid_right:
1672 return KERN_INVALID_RIGHT;
1673 }
1674
1675 /*
1676 * Routine: ipc_right_copyin_undo
1677 * Purpose:
1678 * Undoes the effects of an ipc_right_copyin
1679 * of a send/send-once right that is dead.
1680 * (Object is either IO_DEAD or a dead port.)
1681 * Conditions:
1682 * The space is write-locked and active.
1683 */
1684
1685 void
ipc_right_copyin_undo(ipc_space_t space,mach_port_name_t name,ipc_entry_t entry,mach_msg_type_name_t msgt_name,ipc_object_t object,ipc_port_t soright)1686 ipc_right_copyin_undo(
1687 ipc_space_t space,
1688 mach_port_name_t name,
1689 ipc_entry_t entry,
1690 mach_msg_type_name_t msgt_name,
1691 ipc_object_t object,
1692 ipc_port_t soright)
1693 {
1694 ipc_entry_bits_t bits = entry->ie_bits;
1695
1696 assert(space->is_active);
1697
1698 assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
1699 (msgt_name == MACH_MSG_TYPE_COPY_SEND) ||
1700 (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
1701
1702 if (soright != IP_NULL) {
1703 assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
1704 (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
1705 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
1706 assert(entry->ie_object == IO_NULL);
1707 assert(object != IO_DEAD);
1708
1709 entry->ie_bits = ((bits &~ IE_BITS_RIGHT_MASK) |
1710 MACH_PORT_TYPE_DEAD_NAME | 2);
1711 } else if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE) {
1712 assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
1713 (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
1714 assert(entry->ie_object == IO_NULL);
1715
1716 entry->ie_bits = ((bits &~ IE_BITS_RIGHT_MASK) |
1717 MACH_PORT_TYPE_DEAD_NAME | 1);
1718 } else if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME) {
1719 assert(entry->ie_object == IO_NULL);
1720 assert(object == IO_DEAD);
1721 assert(ipc_entry_refs(entry) > 0);
1722
1723 if (msgt_name != MACH_MSG_TYPE_COPY_SEND) {
1724 ipc_entry_hold(entry);/* increment urefs */
1725 }
1726 } else {
1727 assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
1728 (msgt_name == MACH_MSG_TYPE_COPY_SEND));
1729 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
1730 assert(object != IO_DEAD);
1731 assert(entry->ie_object == object);
1732 assert(ipc_entry_refs(entry) > 0);
1733
1734 if (msgt_name != MACH_MSG_TYPE_COPY_SEND) {
1735 ipc_entry_hold(entry); /* increment urefs */
1736 }
1737
1738 /*
1739 * May as well convert the entry to a dead name.
1740 * (Or if it is a compat entry, destroy it.)
1741 */
1742
1743 if (!ipc_right_check(space, (ipc_port_t) object,
1744 name, entry))
1745 ip_unlock((ipc_port_t) object);
1746 /* object is dead so it is not locked */
1747 }
1748
1749 /* release the reference acquired by copyin */
1750
1751 if (object != IO_DEAD)
1752 ipc_object_release(object);
1753 }
1754
1755 /*
1756 * Routine: ipc_right_copyin_two
1757 * Purpose:
1758 * Like ipc_right_copyin with MACH_MSG_TYPE_MOVE_SEND
1759 * and deadok == FALSE, except that this moves two
1760 * send rights at once.
1761 * Conditions:
1762 * The space is write-locked and active.
1763 * The object is returned with two refs/send rights.
1764 * Returns:
1765 * KERN_SUCCESS Acquired an object.
1766 * KERN_INVALID_RIGHT Name doesn't denote correct right.
1767 */
1768
1769 kern_return_t
ipc_right_copyin_two(ipc_space_t space,mach_port_name_t name,ipc_entry_t entry,ipc_object_t * objectp,ipc_port_t * sorightp)1770 ipc_right_copyin_two(
1771 ipc_space_t space,
1772 mach_port_name_t name,
1773 ipc_entry_t entry,
1774 ipc_object_t *objectp,
1775 ipc_port_t *sorightp)
1776 {
1777 ipc_entry_bits_t bits = entry->ie_bits;
1778 mach_port_urefs_t urefs;
1779 ipc_port_t port;
1780 ipc_port_t dnrequest = IP_NULL;
1781
1782 assert(space->is_active);
1783
1784 if ((bits & MACH_PORT_TYPE_SEND) == 0)
1785 goto invalid_right;
1786
1787 urefs = ipc_entry_refs(entry);
1788 if (urefs < 2)
1789 goto invalid_right;
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 goto invalid_right;
1796 }
1797 /* port is locked and active */
1798
1799 assert(port->ip_srights > 0);
1800
1801 if (urefs == 2) {
1802 if (bits & MACH_PORT_TYPE_RECEIVE) {
1803 assert(port->ip_receiver_name == name);
1804 assert(port->ip_receiver == space);
1805 assert(IE_BITS_TYPE(bits) ==
1806 MACH_PORT_TYPE_SEND_RECEIVE);
1807
1808 port->ip_srights++;
1809 ip_reference(port);
1810 ip_reference(port);
1811 } else {
1812 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
1813
1814 dnrequest = ipc_right_dncancel_macro(space, port,
1815 name, entry);
1816 ipc_hash_delete(space, (ipc_object_t) port,
1817 name, entry);
1818 port->ip_srights++;
1819 ip_reference(port);
1820 OBJECT_CLEAR(entry, name);
1821 }
1822 entry->ie_bits = bits &~
1823 (IE_BITS_UREFS_MASK|MACH_PORT_TYPE_SEND);
1824 } else {
1825 port->ip_srights += 2;
1826 ip_reference(port);
1827 ip_reference(port);
1828 entry->ie_bits = bits-2; /* decrement urefs */
1829 }
1830 ip_unlock(port);
1831
1832 *objectp = (ipc_object_t) port;
1833 *sorightp = dnrequest;
1834 return KERN_SUCCESS;
1835
1836 invalid_right:
1837 return KERN_INVALID_RIGHT;
1838 }
1839
1840 /*
1841 * Routine: ipc_right_copyout
1842 * Purpose:
1843 * Copyout a capability to a space.
1844 * If successful, consumes a ref for the object.
1845 *
1846 * Always succeeds when given a newly-allocated entry,
1847 * because user-reference overflow isn't a possibility.
1848 *
1849 * Conditions:
1850 * The space is write-locked and active.
1851 * The object is locked and active.
1852 * The object is unlocked; the space isn't.
1853 * Returns:
1854 * KERN_SUCCESS Copied out capability.
1855 */
1856
1857 kern_return_t
ipc_right_copyout(ipc_space_t space,mach_port_name_t name,ipc_entry_t entry,mach_msg_type_name_t msgt_name,ipc_object_t object)1858 ipc_right_copyout(
1859 ipc_space_t space,
1860 mach_port_name_t name,
1861 ipc_entry_t entry,
1862 mach_msg_type_name_t msgt_name,
1863 ipc_object_t object)
1864 {
1865 ipc_entry_bits_t bits = entry->ie_bits;
1866 ipc_port_t port;
1867
1868 assert(IO_VALID(object));
1869 assert(io_otype(object) == IOT_PORT);
1870 assert(io_active(object));
1871 assert(entry->ie_object == object);
1872
1873 port = (ipc_port_t) object;
1874
1875 switch (msgt_name) {
1876 case MACH_MSG_TYPE_PORT_SEND_ONCE:
1877 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
1878 assert(port->ip_sorights > 0);
1879
1880 /* transfer send-once right and ref to entry */
1881 ip_unlock(port);
1882
1883 entry->ie_bits = bits | (MACH_PORT_TYPE_SEND_ONCE);
1884 break;
1885
1886 case MACH_MSG_TYPE_PORT_SEND:
1887 assert(port->ip_srights > 0);
1888
1889 if (bits & MACH_PORT_TYPE_SEND) {
1890
1891 assert(port->ip_srights > 1);
1892 assert(ipc_entry_refs(entry) > 0);
1893
1894 port->ip_srights--;
1895 ip_unlock(port);
1896 ip_release(port);
1897 } else if (bits & MACH_PORT_TYPE_RECEIVE) {
1898 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
1899
1900 /* transfer send right to entry */
1901 ip_unlock(port);
1902 ip_release(port);
1903 } else {
1904 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
1905
1906 /* transfer send right and ref to entry */
1907 ip_unlock(port);
1908
1909 /* entry is locked holding ref, so can use port */
1910
1911 ipc_hash_insert(space, (ipc_object_t) port,
1912 name, entry);
1913 }
1914 ipc_entry_hold(entry);
1915 entry->ie_bits = (bits | MACH_PORT_TYPE_SEND);
1916 break;
1917
1918 case MACH_MSG_TYPE_PORT_RECEIVE: {
1919 ipc_port_t dest;
1920
1921 assert(port->ip_mscount == 0);
1922 assert(port->ip_receiver_name == MACH_PORT_NAME_NULL);
1923 dest = port->ip_destination;
1924
1925 port->ip_receiver_name = name;
1926 port->ip_receiver = space;
1927
1928 assert((bits & MACH_PORT_TYPE_RECEIVE) == 0);
1929
1930 if (bits & MACH_PORT_TYPE_SEND) {
1931 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
1932 assert(ipc_entry_refs(entry) > 0);
1933 assert(port->ip_srights > 0);
1934
1935 ip_unlock(port);
1936 ip_release(port);
1937
1938 /* entry is locked holding ref, so can use port */
1939
1940 ipc_hash_delete(space, (ipc_object_t) port,
1941 name, entry);
1942 } else {
1943 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
1944
1945 /* transfer ref to entry */
1946 ip_unlock(port);
1947 }
1948
1949 entry->ie_bits = bits | MACH_PORT_TYPE_RECEIVE;
1950
1951 if (dest != IP_NULL)
1952 ipc_port_release(dest);
1953 break;
1954 }
1955
1956 default:
1957 panic("ipc_right_copyout: strange rights");
1958 }
1959
1960 return KERN_SUCCESS;
1961 }
1962
1963 /*
1964 * Routine: ipc_right_rename
1965 * Purpose:
1966 * Transfer an entry from one name to another.
1967 * The old entry is deallocated.
1968 * Conditions:
1969 * The space is write-locked and active.
1970 * The new entry is unused. Upon return,
1971 * the space is unlocked.
1972 * Returns:
1973 * KERN_SUCCESS Moved entry to new name.
1974 */
1975
1976 kern_return_t
ipc_right_rename(ipc_space_t space,mach_port_name_t oname,ipc_entry_t oentry,mach_port_name_t nname,ipc_entry_t nentry)1977 ipc_right_rename(
1978 ipc_space_t space,
1979 mach_port_name_t oname,
1980 ipc_entry_t oentry,
1981 mach_port_name_t nname,
1982 ipc_entry_t nentry)
1983 {
1984 ipc_entry_bits_t bits = oentry->ie_bits;
1985 ipc_port_request_index_t request = oentry->ie_request;
1986 ipc_object_t object = oentry->ie_object;
1987
1988 assert(space->is_active);
1989 assert(oname != nname);
1990
1991 /*
1992 * If IE_BITS_COMPAT, we can't allow the entry to be renamed
1993 * if the port is dead. (This would foil ipc_port_destroy.)
1994 * Instead we should fail because oentry shouldn't exist.
1995 * Note IE_BITS_COMPAT implies ie_request != 0.
1996 */
1997
1998 if (request != 0) {
1999 ipc_port_t port;
2000
2001 assert(bits & MACH_PORT_TYPE_PORT_RIGHTS);
2002 port = (ipc_port_t) object;
2003 assert(port != IP_NULL);
2004
2005 if (ipc_right_check(space, port, oname, oentry)) {
2006 bits = oentry->ie_bits;
2007 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
2008 assert(oentry->ie_request == 0);
2009 request = 0;
2010 assert(oentry->ie_object == IO_NULL);
2011 object = IO_NULL;
2012 } else {
2013 /* port is locked and active */
2014
2015 ipc_port_dnrename(port, request, oname, nname);
2016 ip_unlock(port);
2017 oentry->ie_request = 0;
2018 }
2019 }
2020
2021 /* initialize nentry before letting ipc_hash_insert see it */
2022
2023 assert((nentry->ie_bits & IE_BITS_RIGHT_MASK) == 0);
2024 nentry->ie_bits |= bits & IE_BITS_RIGHT_MASK;
2025 nentry->ie_request = request;
2026 nentry->ie_object = object;
2027
2028 switch (IE_BITS_TYPE(bits)) {
2029 case MACH_PORT_TYPE_SEND: {
2030 ipc_port_t port;
2031
2032 port = (ipc_port_t) object;
2033 assert(port != IP_NULL);
2034
2035 ipc_hash_delete(space, (ipc_object_t) port, oname, oentry);
2036 ipc_hash_insert(space, (ipc_object_t) port, nname, nentry);
2037 break;
2038 }
2039
2040 case MACH_PORT_TYPE_RECEIVE:
2041 case MACH_PORT_TYPE_SEND_RECEIVE: {
2042 ipc_port_t port;
2043
2044 port = (ipc_port_t) object;
2045 assert(port != IP_NULL);
2046
2047 ip_lock(port);
2048 assert(ip_active(port));
2049 assert(port->ip_receiver_name == oname);
2050 assert(port->ip_receiver == space);
2051
2052 port->ip_receiver_name = nname;
2053 ip_unlock(port);
2054 break;
2055 }
2056
2057 case MACH_PORT_TYPE_PORT_SET: {
2058 ipc_pset_t pset;
2059
2060 pset = (ipc_pset_t) object;
2061 assert(pset != IPS_NULL);
2062
2063 ips_lock(pset);
2064 assert(ips_active(pset));
2065 assert(pset->ips_local_name == oname);
2066
2067 pset->ips_local_name = nname;
2068 ips_unlock(pset);
2069 break;
2070 }
2071
2072 case MACH_PORT_TYPE_SEND_ONCE:
2073 case MACH_PORT_TYPE_DEAD_NAME:
2074 break;
2075
2076 default:
2077 panic("ipc_right_rename: strange rights");
2078 }
2079
2080 assert(oentry->ie_request == 0);
2081 OBJECT_CLEAR(oentry, oname);
2082 /* drops the space lock */
2083 ipc_entry_dealloc(space, oname, oentry);
2084
2085 return KERN_SUCCESS;
2086 }
2087