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