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