|
|
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: * File: ipc/ipc_object.c
28: * Author: Rich Draves
29: * Date: 1989
30: *
31: * Functions to manipulate IPC objects.
32: */
33:
34: #include <mach_ipc_compat.h>
35:
36: #include <mach/boolean.h>
37: #include <mach/kern_return.h>
38: #include <mach/port.h>
39: #include <mach/message.h>
40: #include <ipc/port.h>
41: #include <ipc/ipc_space.h>
42: #include <ipc/ipc_entry.h>
43: #include <ipc/ipc_object.h>
44: #include <ipc/ipc_hash.h>
45: #include <ipc/ipc_right.h>
46: #include <ipc/ipc_notify.h>
47: #include <ipc/ipc_pset.h>
48:
49: zone_t ipc_object_zones[IOT_NUMBER];
50:
51:
52:
53: /*
54: * Routine: ipc_object_reference
55: * Purpose:
56: * Take a reference to an object.
57: */
58:
59: void
60: ipc_object_reference(
61: ipc_object_t object)
62: {
63: io_lock(object);
64: assert(object->io_references > 0);
65: io_reference(object);
66: io_unlock(object);
67: }
68:
69: /*
70: * Routine: ipc_object_release
71: * Purpose:
72: * Release a reference to an object.
73: */
74:
75: void
76: ipc_object_release(
77: ipc_object_t object)
78: {
79: io_lock(object);
80: assert(object->io_references > 0);
81: io_release(object);
82: io_check_unlock(object);
83: }
84:
85: /*
86: * Routine: ipc_object_translate
87: * Purpose:
88: * Look up an object in a space.
89: * Conditions:
90: * Nothing locked before. If successful, the object
91: * is returned locked. The caller doesn't get a ref.
92: * Returns:
93: * KERN_SUCCESS Objected returned locked.
94: * KERN_INVALID_TASK The space is dead.
95: * KERN_INVALID_NAME The name doesn't denote a right.
96: * KERN_INVALID_RIGHT Name doesn't denote the correct right.
97: */
98:
99: kern_return_t
100: ipc_object_translate(
101: ipc_space_t space,
102: mach_port_t name,
103: mach_port_right_t right,
104: ipc_object_t *objectp)
105: {
106: ipc_entry_t entry;
107: ipc_object_t object;
108: kern_return_t kr;
109:
110: kr = ipc_right_lookup_read(space, name, &entry);
111: if (kr != KERN_SUCCESS)
112: return kr;
113: /* space is read-locked and active */
114:
115: if ((entry->ie_bits & MACH_PORT_TYPE(right)) == (mach_port_right_t) 0) {
116: is_read_unlock(space);
117: return KERN_INVALID_RIGHT;
118: }
119:
120: object = entry->ie_object;
121: assert(object != IO_NULL);
122:
123: io_lock(object);
124: is_read_unlock(space);
125:
126: *objectp = object;
127: return KERN_SUCCESS;
128: }
129:
130: /*
131: * Routine: ipc_object_alloc_dead
132: * Purpose:
133: * Allocate a dead-name entry.
134: * Conditions:
135: * Nothing locked.
136: * Returns:
137: * KERN_SUCCESS The dead name is allocated.
138: * KERN_INVALID_TASK The space is dead.
139: * KERN_NO_SPACE No room for an entry in the space.
140: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
141: */
142:
143: kern_return_t
144: ipc_object_alloc_dead(
145: ipc_space_t space,
146: mach_port_t *namep)
147: {
148: ipc_entry_t entry;
149: kern_return_t kr;
150:
151:
152: kr = ipc_entry_alloc(space, namep, &entry);
153: if (kr != KERN_SUCCESS)
154: return kr;
155: /* space is write-locked */
156:
157: /* null object, MACH_PORT_TYPE_DEAD_NAME, 1 uref */
158:
159: assert(entry->ie_object == IO_NULL);
160: entry->ie_bits |= MACH_PORT_TYPE_DEAD_NAME | 1;
161:
162: is_write_unlock(space);
163: return KERN_SUCCESS;
164: }
165:
166: /*
167: * Routine: ipc_object_alloc_dead_name
168: * Purpose:
169: * Allocate a dead-name entry, with a specific name.
170: * Conditions:
171: * Nothing locked.
172: * Returns:
173: * KERN_SUCCESS The dead name is allocated.
174: * KERN_INVALID_TASK The space is dead.
175: * KERN_NAME_EXISTS The name already denotes a right.
176: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
177: */
178:
179: kern_return_t
180: ipc_object_alloc_dead_name(
181: ipc_space_t space,
182: mach_port_t name)
183: {
184: ipc_entry_t entry;
185: kern_return_t kr;
186:
187:
188: kr = ipc_entry_alloc_name(space, name, &entry);
189: if (kr != KERN_SUCCESS)
190: return kr;
191: /* space is write-locked */
192:
193: if (ipc_right_inuse(space, name, entry))
194: return KERN_NAME_EXISTS;
195:
196: /* null object, MACH_PORT_TYPE_DEAD_NAME, 1 uref */
197:
198: assert(entry->ie_object == IO_NULL);
199: entry->ie_bits |= MACH_PORT_TYPE_DEAD_NAME | 1;
200:
201: is_write_unlock(space);
202: return KERN_SUCCESS;
203: }
204:
205: /*
206: * Routine: ipc_object_alloc
207: * Purpose:
208: * Allocate an object.
209: * Conditions:
210: * Nothing locked. If successful, the object is returned locked.
211: * The caller doesn't get a reference for the object.
212: * Returns:
213: * KERN_SUCCESS The object is allocated.
214: * KERN_INVALID_TASK The space is dead.
215: * KERN_NO_SPACE No room for an entry in the space.
216: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
217: */
218:
219: kern_return_t
220: ipc_object_alloc(
221: ipc_space_t space,
222: ipc_object_type_t otype,
223: mach_port_type_t type,
224: mach_port_urefs_t urefs,
225: mach_port_t *namep,
226: ipc_object_t *objectp)
227: {
228: ipc_object_t object;
229: ipc_entry_t entry;
230: kern_return_t kr;
231:
232: assert(otype < IOT_NUMBER);
233: assert((type & MACH_PORT_TYPE_ALL_RIGHTS) == type);
234: assert(type != MACH_PORT_TYPE_NONE);
235: assert(urefs <= MACH_PORT_UREFS_MAX);
236:
237: object = io_alloc(otype);
238: if (object == IO_NULL)
239: return KERN_RESOURCE_SHORTAGE;
240:
241: if (otype == IOT_PORT) {
242: ipc_port_t port = (ipc_port_t)object;
243:
244: bzero((char *)port, sizeof(*port));
245: } else if (otype == IOT_PORT_SET) {
246: ipc_pset_t pset = (ipc_pset_t)object;
247:
248: bzero((char *)pset, sizeof(*pset));
249: }
250: kr = ipc_entry_alloc(space, namep, &entry);
251: if (kr != KERN_SUCCESS) {
252: io_free(otype, object);
253: return kr;
254: }
255: /* space is write-locked */
256:
257: entry->ie_bits |= type | urefs;
258: entry->ie_object = object;
259:
260: io_lock_init(object);
261: io_lock(object);
262: is_write_unlock(space);
263:
264: object->io_references = 1; /* for entry, not caller */
265: object->io_bits = io_makebits(TRUE, otype, 0);
266:
267: *objectp = object;
268: return KERN_SUCCESS;
269: }
270:
271: /*
272: * Routine: ipc_object_alloc_name
273: * Purpose:
274: * Allocate an object, with a specific name.
275: * Conditions:
276: * Nothing locked. If successful, the object is returned locked.
277: * The caller doesn't get a reference for the object.
278: * Returns:
279: * KERN_SUCCESS The object is allocated.
280: * KERN_INVALID_TASK The space is dead.
281: * KERN_NAME_EXISTS The name already denotes a right.
282: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
283: */
284:
285: kern_return_t
286: ipc_object_alloc_name(
287: ipc_space_t space,
288: ipc_object_type_t otype,
289: mach_port_type_t type,
290: mach_port_urefs_t urefs,
291: mach_port_t name,
292: ipc_object_t *objectp)
293: {
294: ipc_object_t object;
295: ipc_entry_t entry;
296: kern_return_t kr;
297:
298: assert(otype < IOT_NUMBER);
299: assert((type & MACH_PORT_TYPE_ALL_RIGHTS) == type);
300: assert(type != MACH_PORT_TYPE_NONE);
301: assert(urefs <= MACH_PORT_UREFS_MAX);
302:
303: object = io_alloc(otype);
304: if (object == IO_NULL)
305: return KERN_RESOURCE_SHORTAGE;
306:
307: if (otype == IOT_PORT) {
308: ipc_port_t port = (ipc_port_t)object;
309:
310: bzero((char *)port, sizeof(*port));
311: } else if (otype == IOT_PORT_SET) {
312: ipc_pset_t pset = (ipc_pset_t)object;
313:
314: bzero((char *)pset, sizeof(*pset));
315: }
316:
317: kr = ipc_entry_alloc_name(space, name, &entry);
318: if (kr != KERN_SUCCESS) {
319: io_free(otype, object);
320: return kr;
321: }
322: /* space is write-locked */
323:
324: if (ipc_right_inuse(space, name, entry)) {
325: io_free(otype, object);
326: return KERN_NAME_EXISTS;
327: }
328:
329: entry->ie_bits |= type | urefs;
330: entry->ie_object = object;
331:
332: io_lock_init(object);
333: io_lock(object);
334: is_write_unlock(space);
335:
336: object->io_references = 1; /* for entry, not caller */
337: object->io_bits = io_makebits(TRUE, otype, 0);
338:
339: *objectp = object;
340: return KERN_SUCCESS;
341: }
342:
343: /*
344: * Routine: ipc_object_copyin_type
345: * Purpose:
346: * Convert a send type name to a received type name.
347: */
348:
349: mach_msg_type_name_t
350: ipc_object_copyin_type(
351: mach_msg_type_name_t msgt_name)
352: {
353: switch (msgt_name) {
354: case 0:
355: return 0;
356:
357: case MACH_MSG_TYPE_MOVE_RECEIVE:
358: return MACH_MSG_TYPE_PORT_RECEIVE;
359:
360: case MACH_MSG_TYPE_MOVE_SEND_ONCE:
361: case MACH_MSG_TYPE_MAKE_SEND_ONCE:
362: return MACH_MSG_TYPE_PORT_SEND_ONCE;
363:
364: case MACH_MSG_TYPE_MOVE_SEND:
365: case MACH_MSG_TYPE_MAKE_SEND:
366: case MACH_MSG_TYPE_COPY_SEND:
367: return MACH_MSG_TYPE_PORT_SEND;
368:
369: #if MACH_IPC_COMPAT
370: case MSG_TYPE_PORT:
371: return MACH_MSG_TYPE_PORT_SEND;
372:
373: case MSG_TYPE_PORT_ALL:
374: return MACH_MSG_TYPE_PORT_RECEIVE;
375: #endif /* MACH_IPC_COMPAT */
376:
377: default:
378: #if MACH_ASSERT
379: assert(!"ipc_object_copyin_type: strange rights");
380: #else
381: panic("ipc_object_copyin_type: strange rights");
382: #endif
383: return 0; /* in case assert/panic returns */
384: }
385: }
386:
387: /*
388: * Routine: ipc_object_copyin
389: * Purpose:
390: * Copyin a capability from a space.
391: * If successful, the caller gets a ref
392: * for the resulting object, unless it is IO_DEAD.
393: * Conditions:
394: * Nothing locked.
395: * Returns:
396: * KERN_SUCCESS Acquired an object, possibly IO_DEAD.
397: * KERN_INVALID_TASK The space is dead.
398: * KERN_INVALID_NAME Name doesn't exist in space.
399: * KERN_INVALID_RIGHT Name doesn't denote correct right.
400: */
401:
402: kern_return_t
403: ipc_object_copyin(
404: ipc_space_t space,
405: mach_port_t name,
406: mach_msg_type_name_t msgt_name,
407: ipc_object_t *objectp)
408: {
409: ipc_entry_t entry;
410: ipc_port_t soright;
411: kern_return_t kr;
412:
413: /*
414: * Could first try a read lock when doing
415: * MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND,
416: * and MACH_MSG_TYPE_MAKE_SEND_ONCE.
417: */
418:
419: kr = ipc_right_lookup_write(space, name, &entry);
420: if (kr != KERN_SUCCESS)
421: return kr;
422: /* space is write-locked and active */
423:
424: kr = ipc_right_copyin(space, name, entry,
425: msgt_name, TRUE,
426: objectp, &soright);
427: if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
428: ipc_entry_dealloc(space, name, entry);
429: is_write_unlock(space);
430:
431: if ((kr == KERN_SUCCESS) && (soright != IP_NULL))
432: ipc_notify_port_deleted(soright, name);
433:
434: return kr;
435: }
436:
437: /*
438: * Routine: ipc_object_copyin_from_kernel
439: * Purpose:
440: * Copyin a naked capability from the kernel.
441: *
442: * MACH_MSG_TYPE_MOVE_RECEIVE
443: * The receiver must be ipc_space_kernel.
444: * Consumes the naked receive right.
445: * MACH_MSG_TYPE_COPY_SEND
446: * A naked send right must be supplied.
447: * The port gains a reference, and a send right
448: * if the port is still active.
449: * MACH_MSG_TYPE_MAKE_SEND
450: * The receiver must be ipc_space_kernel.
451: * The port gains a reference and a send right.
452: * MACH_MSG_TYPE_MOVE_SEND
453: * Consumes a naked send right.
454: * MACH_MSG_TYPE_MAKE_SEND_ONCE
455: * The receiver must be ipc_space_kernel.
456: * The port gains a reference and a send-once right.
457: * MACH_MSG_TYPE_MOVE_SEND_ONCE
458: * Consumes a naked send-once right.
459: * Conditions:
460: * Nothing locked.
461: */
462:
463: void
464: ipc_object_copyin_from_kernel(
465: ipc_object_t object,
466: mach_msg_type_name_t msgt_name)
467: {
468: assert(IO_VALID(object));
469:
470: switch (msgt_name) {
471: case MACH_MSG_TYPE_MOVE_RECEIVE: {
472: ipc_port_t port = (ipc_port_t) object;
473:
474: ip_lock(port);
475: assert(ip_active(port));
476: assert(port->ip_receiver_name != MACH_PORT_NULL);
477: assert(port->ip_receiver == ipc_space_kernel);
478:
479: /* relevant part of ipc_port_clear_receiver */
480: ipc_port_set_mscount(port, 0);
481:
482: port->ip_receiver_name = MACH_PORT_NULL;
483: port->ip_destination = IP_NULL;
484: ip_unlock(port);
485: break;
486: }
487:
488: case MACH_MSG_TYPE_COPY_SEND: {
489: ipc_port_t port = (ipc_port_t) object;
490:
491: ip_lock(port);
492: if (ip_active(port)) {
493: assert(port->ip_srights > 0);
494: port->ip_srights++;
495: }
496: ip_reference(port);
497: ip_unlock(port);
498: break;
499: }
500:
501: case MACH_MSG_TYPE_MAKE_SEND: {
502: ipc_port_t port = (ipc_port_t) object;
503:
504: ip_lock(port);
505: assert(ip_active(port));
506: assert(port->ip_receiver_name != MACH_PORT_NULL);
507: assert(port->ip_receiver == ipc_space_kernel);
508:
509: ip_reference(port);
510: port->ip_mscount++;
511: port->ip_srights++;
512: ip_unlock(port);
513: break;
514: }
515:
516: case MACH_MSG_TYPE_MOVE_SEND:
517: /* move naked send right into the message */
518: break;
519:
520: case MACH_MSG_TYPE_MAKE_SEND_ONCE: {
521: ipc_port_t port = (ipc_port_t) object;
522:
523: ip_lock(port);
524: assert(ip_active(port));
525: assert(port->ip_receiver_name != MACH_PORT_NULL);
526: assert(port->ip_receiver == ipc_space_kernel);
527:
528: ip_reference(port);
529: port->ip_sorights++;
530: ip_unlock(port);
531: break;
532: }
533:
534: case MACH_MSG_TYPE_MOVE_SEND_ONCE:
535: /* move naked send-once right into the message */
536: break;
537:
538: default:
539: #if MACH_ASSERT
540: assert(!"ipc_object_copyin_from_kernel: strange rights");
541: #else
542: panic("ipc_object_copyin_from_kernel: strange rights");
543: #endif
544: }
545: }
546:
547: /*
548: * Routine: ipc_object_destroy
549: * Purpose:
550: * Destroys a naked capability.
551: * Consumes a ref for the object.
552: *
553: * A receive right should be in limbo or in transit.
554: * Conditions:
555: * Nothing locked.
556: */
557:
558: void
559: ipc_object_destroy(
560: ipc_object_t object,
561: mach_msg_type_name_t msgt_name)
562: {
563: assert(IO_VALID(object));
564: assert(io_otype(object) == IOT_PORT);
565:
566: switch (msgt_name) {
567: case MACH_MSG_TYPE_PORT_SEND:
568: ipc_port_release_send((ipc_port_t) object);
569: break;
570:
571: case MACH_MSG_TYPE_PORT_SEND_ONCE:
572: ipc_notify_send_once((ipc_port_t) object);
573: break;
574:
575: case MACH_MSG_TYPE_PORT_RECEIVE:
576: ipc_port_release_receive((ipc_port_t) object);
577: break;
578:
579: default:
580: panic("ipc_object_destroy: strange rights");
581: }
582: }
583:
584: /*
585: * Routine: ipc_object_copyout
586: * Purpose:
587: * Copyout a capability, placing it into a space.
588: * If successful, consumes a ref for the object.
589: * Conditions:
590: * Nothing locked.
591: * Returns:
592: * KERN_SUCCESS Copied out object, consumed ref.
593: * KERN_INVALID_TASK The space is dead.
594: * KERN_INVALID_CAPABILITY The object is dead.
595: * KERN_NO_SPACE No room in space for another right.
596: * KERN_RESOURCE_SHORTAGE No memory available.
597: * KERN_UREFS_OVERFLOW Urefs limit exceeded
598: * and overflow wasn't specified.
599: */
600:
601: kern_return_t
602: ipc_object_copyout(
603: ipc_space_t space,
604: ipc_object_t object,
605: mach_msg_type_name_t msgt_name,
606: boolean_t overflow,
607: mach_port_t *namep)
608: {
609: mach_port_t name;
610: ipc_entry_t entry;
611: kern_return_t kr;
612:
613: assert(IO_VALID(object));
614: assert(io_otype(object) == IOT_PORT);
615:
616: is_write_lock(space);
617:
618: for (;;) {
619: if (!space->is_active) {
620: is_write_unlock(space);
621: return KERN_INVALID_TASK;
622: }
623:
624: if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
625: ipc_right_reverse(space, object, &name, &entry)) {
626: /* object is locked and active */
627:
628: assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
629: break;
630: }
631:
632: kr = ipc_entry_get(space, &name, &entry);
633: if (kr != KERN_SUCCESS) {
634: /* unlocks/locks space, so must start again */
635:
636: kr = ipc_entry_grow_table(space);
637: if (kr != KERN_SUCCESS)
638: return kr; /* space is unlocked */
639:
640: continue;
641: }
642:
643: assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE);
644: assert(entry->ie_object == IO_NULL);
645:
646: io_lock(object);
647: if (!io_active(object)) {
648: io_unlock(object);
649: ipc_entry_dealloc(space, name, entry);
650: is_write_unlock(space);
651: return KERN_INVALID_CAPABILITY;
652: }
653:
654: entry->ie_object = object;
655: break;
656: }
657:
658: /* space is write-locked and active, object is locked and active */
659:
660: kr = ipc_right_copyout(space, name, entry,
661: msgt_name, overflow, object);
662: /* object is unlocked */
663: is_write_unlock(space);
664:
665: if (kr == KERN_SUCCESS)
666: *namep = name;
667: return kr;
668: }
669:
670: #if 0
671: /* XXX same, but don't check for already-existing send rights */
672: kern_return_t
673: ipc_object_copyout_multiname(space, object, namep)
674: ipc_space_t space;
675: ipc_object_t object;
676: mach_port_t *namep;
677: {
678: mach_port_t name;
679: ipc_entry_t entry;
680: kern_return_t kr;
681:
682: assert(IO_VALID(object));
683: assert(io_otype(object) == IOT_PORT);
684:
685: is_write_lock(space);
686:
687: for (;;) {
688: if (!space->is_active) {
689: is_write_unlock(space);
690: return KERN_INVALID_TASK;
691: }
692:
693: kr = ipc_entry_get(space, &name, &entry);
694: if (kr != KERN_SUCCESS) {
695: /* unlocks/locks space, so must start again */
696:
697: kr = ipc_entry_grow_table(space);
698: if (kr != KERN_SUCCESS)
699: return kr; /* space is unlocked */
700:
701: continue;
702: }
703:
704: assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE);
705: assert(entry->ie_object == IO_NULL);
706:
707: io_lock(object);
708: if (!io_active(object)) {
709: io_unlock(object);
710: ipc_entry_dealloc(space, name, entry);
711: is_write_unlock(space);
712: return KERN_INVALID_CAPABILITY;
713: }
714:
715: entry->ie_object = object;
716: break;
717: }
718:
719: /* space is write-locked and active, object is locked and active */
720:
721: kr = ipc_right_copyout_multiname(space, name, entry, object);
722: /* object is unlocked */
723: is_write_unlock(space);
724:
725: if (kr == KERN_SUCCESS)
726: *namep = name;
727: return kr;
728: }
729: #endif /* 0 */
730:
731: /*
732: * Routine: ipc_object_copyout_name
733: * Purpose:
734: * Copyout a capability, placing it into a space.
735: * The specified name is used for the capability.
736: * If successful, consumes a ref for the object.
737: * Conditions:
738: * Nothing locked.
739: * Returns:
740: * KERN_SUCCESS Copied out object, consumed ref.
741: * KERN_INVALID_TASK The space is dead.
742: * KERN_INVALID_CAPABILITY The object is dead.
743: * KERN_RESOURCE_SHORTAGE No memory available.
744: * KERN_UREFS_OVERFLOW Urefs limit exceeded
745: * and overflow wasn't specified.
746: * KERN_RIGHT_EXISTS Space has rights under another name.
747: * KERN_NAME_EXISTS Name is already used.
748: */
749:
750: kern_return_t
751: ipc_object_copyout_name(
752: ipc_space_t space,
753: ipc_object_t object,
754: mach_msg_type_name_t msgt_name,
755: boolean_t overflow,
756: mach_port_t name)
757: {
758: mach_port_t oname;
759: ipc_entry_t oentry;
760: ipc_entry_t entry;
761: kern_return_t kr;
762:
763: assert(IO_VALID(object));
764: assert(io_otype(object) == IOT_PORT);
765:
766: kr = ipc_entry_alloc_name(space, name, &entry);
767: if (kr != KERN_SUCCESS)
768: return kr;
769: /* space is write-locked and active */
770:
771: if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
772: ipc_right_reverse(space, object, &oname, &oentry)) {
773: /* object is locked and active */
774:
775: if (name != oname) {
776: io_unlock(object);
777:
778: if (IE_BITS_TYPE(entry->ie_bits)
779: == MACH_PORT_TYPE_NONE)
780: ipc_entry_dealloc(space, name, entry);
781:
782: is_write_unlock(space);
783: return KERN_RIGHT_EXISTS;
784: }
785:
786: assert(entry == oentry);
787: assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
788: } else {
789: if (ipc_right_inuse(space, name, entry))
790: return KERN_NAME_EXISTS;
791:
792: assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE);
793: assert(entry->ie_object == IO_NULL);
794:
795: io_lock(object);
796: if (!io_active(object)) {
797: io_unlock(object);
798: ipc_entry_dealloc(space, name, entry);
799: is_write_unlock(space);
800: return KERN_INVALID_CAPABILITY;
801: }
802:
803: entry->ie_object = object;
804: }
805:
806: /* space is write-locked and active, object is locked and active */
807:
808: kr = ipc_right_copyout(space, name, entry,
809: msgt_name, overflow, object);
810: /* object is unlocked */
811: is_write_unlock(space);
812: return kr;
813: }
814:
815: /*
816: * Routine: ipc_object_copyout_dest
817: * Purpose:
818: * Translates/consumes the destination right of a message.
819: * This is unlike normal copyout because the right is consumed
820: * in a funny way instead of being given to the receiving space.
821: * The receiver gets his name for the port, if he has receive
822: * rights, otherwise MACH_PORT_NULL.
823: * Conditions:
824: * The object is locked and active. Nothing else locked.
825: * The object is unlocked and loses a reference.
826: */
827:
828: void
829: ipc_object_copyout_dest(
830: ipc_space_t space,
831: ipc_object_t object,
832: mach_msg_type_name_t msgt_name,
833: mach_port_t *namep)
834: {
835: mach_port_t name;
836:
837: assert(IO_VALID(object));
838: assert(io_active(object));
839:
840: io_release(object);
841:
842: /*
843: * If the space is the receiver/owner of the object,
844: * then we quietly consume the right and return
845: * the space's name for the object. Otherwise
846: * we destroy the right and return MACH_PORT_NULL.
847: */
848:
849: switch (msgt_name) {
850: case MACH_MSG_TYPE_PORT_SEND: {
851: ipc_port_t port = (ipc_port_t) object;
852: ipc_port_t nsrequest = IP_NULL;
853: mach_port_mscount_t mscount = 0; /* '=0' to shut up lint */
854:
855: assert(port->ip_srights > 0);
856: if (--port->ip_srights == 0) {
857: nsrequest = port->ip_nsrequest;
858: if (nsrequest != IP_NULL) {
859: port->ip_nsrequest = IP_NULL;
860: mscount = port->ip_mscount;
861: }
862: }
863:
864: if (port->ip_receiver == space)
865: name = port->ip_receiver_name;
866: else
867: name = MACH_PORT_NULL;
868:
869: ip_unlock(port);
870:
871: if (nsrequest != IP_NULL)
872: ipc_notify_no_senders(nsrequest, mscount);
873:
874: break;
875: }
876:
877: case MACH_MSG_TYPE_PORT_SEND_ONCE: {
878: ipc_port_t port = (ipc_port_t) object;
879:
880: assert(port->ip_sorights > 0);
881:
882: if (port->ip_receiver == space) {
883: /* quietly consume the send-once right */
884:
885: port->ip_sorights--;
886: name = port->ip_receiver_name;
887: ip_unlock(port);
888: } else {
889: /*
890: * A very bizarre case. The message
891: * was received, but before this copyout
892: * happened the space lost receive rights.
893: * We can't quietly consume the soright
894: * out from underneath some other task,
895: * so generate a send-once notification.
896: */
897:
898: ip_reference(port); /* restore ref */
899: ip_unlock(port);
900:
901: ipc_notify_send_once(port);
902: name = MACH_PORT_NULL;
903: }
904:
905: break;
906: }
907:
908: default:
909: #if MACH_ASSERT
910: assert(!"ipc_object_copyout_dest: strange rights");
911: #else
912: panic("ipc_object_copyout_dest: strange rights");
913: #endif
914:
915: }
916:
917: *namep = name;
918: }
919:
920: /*
921: * Routine: ipc_object_rename
922: * Purpose:
923: * Rename an entry in a space.
924: * Conditions:
925: * Nothing locked.
926: * Returns:
927: * KERN_SUCCESS Renamed the entry.
928: * KERN_INVALID_TASK The space was dead.
929: * KERN_INVALID_NAME oname didn't denote an entry.
930: * KERN_NAME_EXISTS nname already denoted an entry.
931: * KERN_RESOURCE_SHORTAGE Couldn't allocate new entry.
932: */
933:
934: kern_return_t
935: ipc_object_rename(
936: ipc_space_t space,
937: mach_port_t oname,
938: mach_port_t nname)
939: {
940: ipc_entry_t oentry, nentry;
941: kern_return_t kr;
942:
943: kr = ipc_entry_alloc_name(space, nname, &nentry);
944: if (kr != KERN_SUCCESS)
945: return kr;
946: /* space is write-locked and active */
947:
948: if (ipc_right_inuse(space, nname, nentry)) {
949: /* space is unlocked */
950: return KERN_NAME_EXISTS;
951: }
952:
953: /* don't let ipc_entry_lookup see the uninitialized new entry */
954:
955: if ((oname == nname) ||
956: ((oentry = ipc_entry_lookup(space, oname)) == IE_NULL)) {
957: ipc_entry_dealloc(space, nname, nentry);
958: is_write_unlock(space);
959: return KERN_INVALID_NAME;
960: }
961:
962: kr = ipc_right_rename(space, oname, oentry, nname, nentry);
963: /* space is unlocked */
964: return kr;
965: }
966:
967: #if MACH_IPC_COMPAT
968:
969: /*
970: * Routine: ipc_object_copyout_type_compat
971: * Purpose:
972: * Convert a carried type name to an old type name.
973: */
974:
975: mach_msg_type_name_t
976: ipc_object_copyout_type_compat(msgt_name)
977: mach_msg_type_name_t msgt_name;
978: {
979: switch (msgt_name) {
980: case MACH_MSG_TYPE_PORT_SEND:
981: case MACH_MSG_TYPE_PORT_SEND_ONCE:
982: return MSG_TYPE_PORT;
983:
984: case MACH_MSG_TYPE_PORT_RECEIVE:
985: return MSG_TYPE_PORT_ALL;
986:
987: default:
988: #if MACH_ASSERT
989: assert(!"ipc_object_copyout_type_compat: strange rights");
990: #else
991: panic("ipc_object_copyout_type_compat: strange rights");
992: #endif
993: }
994: }
995:
996: /*
997: * Routine: ipc_object_copyin_compat
998: * Purpose:
999: * Copyin a capability from a space.
1000: * If successful, the caller gets a ref
1001: * for the resulting object, which is always valid.
1002: * Conditions:
1003: * Nothing locked.
1004: * Returns:
1005: * KERN_SUCCESS Acquired a valid object.
1006: * KERN_INVALID_TASK The space is dead.
1007: * KERN_INVALID_NAME Name doesn't exist in space.
1008: * KERN_INVALID_RIGHT Name doesn't denote correct right.
1009: */
1010:
1011: kern_return_t
1012: ipc_object_copyin_compat(space, name, msgt_name, dealloc, objectp)
1013: ipc_space_t space;
1014: mach_port_t name;
1015: mach_msg_type_name_t msgt_name;
1016: boolean_t dealloc;
1017: ipc_object_t *objectp;
1018: {
1019: ipc_entry_t entry;
1020: kern_return_t kr;
1021:
1022: kr = ipc_right_lookup_write(space, name, &entry);
1023: if (kr != KERN_SUCCESS)
1024: return kr;
1025: /* space is write-locked and active */
1026:
1027: kr = ipc_right_copyin_compat(space, name, entry,
1028: msgt_name, dealloc, objectp);
1029: /* space is unlocked */
1030: return kr;
1031: }
1032:
1033: /*
1034: * Routine: ipc_object_copyin_header
1035: * Purpose:
1036: * Copyin a capability from a space.
1037: * If successful, the caller gets a ref
1038: * for the resulting object, which is always valid.
1039: * The type of the acquired capability is returned.
1040: * Conditions:
1041: * Nothing locked.
1042: * Returns:
1043: * KERN_SUCCESS Acquired a valid object.
1044: * KERN_INVALID_TASK The space is dead.
1045: * KERN_INVALID_NAME Name doesn't exist in space.
1046: * KERN_INVALID_RIGHT Name doesn't denote correct right.
1047: */
1048:
1049: kern_return_t
1050: ipc_object_copyin_header(space, name, objectp, msgt_namep)
1051: ipc_space_t space;
1052: mach_port_t name;
1053: ipc_object_t *objectp;
1054: mach_msg_type_name_t *msgt_namep;
1055: {
1056: ipc_entry_t entry;
1057: kern_return_t kr;
1058:
1059: kr = ipc_right_lookup_write(space, name, &entry);
1060: if (kr != KERN_SUCCESS)
1061: return kr;
1062: /* space is write-locked and active */
1063:
1064: kr = ipc_right_copyin_header(space, name, entry,
1065: objectp, msgt_namep);
1066: /* space is unlocked */
1067: return kr;
1068: }
1069:
1070: /*
1071: * Routine: ipc_object_copyout_compat
1072: * Purpose:
1073: * Copyout a capability, placing it into a space.
1074: * If successful, consumes a ref for the object.
1075: *
1076: * Marks new entries with IE_BITS_COMPAT.
1077: * Conditions:
1078: * Nothing locked.
1079: * Returns:
1080: * KERN_SUCCESS Copied out object, consumed ref.
1081: * KERN_INVALID_TASK The space is dead.
1082: * KERN_INVALID_CAPABILITY The object is dead.
1083: * KERN_NO_SPACE No room in space for another right.
1084: * KERN_RESOURCE_SHORTAGE No memory available.
1085: */
1086:
1087: kern_return_t
1088: ipc_object_copyout_compat(space, object, msgt_name, namep)
1089: ipc_space_t space;
1090: ipc_object_t object;
1091: mach_msg_type_name_t msgt_name;
1092: mach_port_t *namep;
1093: {
1094: mach_port_t name;
1095: ipc_entry_t entry;
1096: ipc_port_t port;
1097: kern_return_t kr;
1098:
1099: assert(IO_VALID(object));
1100: assert(io_otype(object) == IOT_PORT);
1101: port = (ipc_port_t) object;
1102:
1103: is_write_lock(space);
1104:
1105: for (;;) {
1106: ipc_port_request_index_t request;
1107:
1108: if (!space->is_active) {
1109: is_write_unlock(space);
1110: return KERN_INVALID_TASK;
1111: }
1112:
1113: if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
1114: ipc_right_reverse(space, (ipc_object_t) port,
1115: &name, &entry)) {
1116: /* port is locked and active */
1117:
1118: assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
1119: break;
1120: }
1121:
1122: kr = ipc_entry_get(space, &name, &entry);
1123: if (kr != KERN_SUCCESS) {
1124: /* unlocks/locks space, so must start again */
1125:
1126: kr = ipc_entry_grow_table(space);
1127: if (kr != KERN_SUCCESS)
1128: return kr; /* space is unlocked */
1129:
1130: continue;
1131: }
1132:
1133: assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE);
1134: assert(entry->ie_object == IO_NULL);
1135:
1136: ip_lock(port);
1137: if (!ip_active(port)) {
1138: ip_unlock(port);
1139: ipc_entry_dealloc(space, name, entry);
1140: is_write_unlock(space);
1141: return KERN_INVALID_CAPABILITY;
1142: }
1143:
1144: kr = ipc_port_dnrequest(port, name, ipr_spacem(space),
1145: &request);
1146: if (kr != KERN_SUCCESS) {
1147: ipc_entry_dealloc(space, name, entry);
1148: is_write_unlock(space);
1149:
1150: kr = ipc_port_dngrow(port);
1151: /* port is unlocked */
1152: if (kr != KERN_SUCCESS)
1153: return kr;
1154:
1155: is_write_lock(space);
1156: continue;
1157: }
1158:
1159: is_reference(space); /* for dnrequest */
1160: entry->ie_object = (ipc_object_t) port;
1161: entry->ie_request = request;
1162: entry->ie_bits |= IE_BITS_COMPAT;
1163: break;
1164: }
1165:
1166: /* space is write-locked and active, port is locked and active */
1167:
1168: kr = ipc_right_copyout(space, name, entry,
1169: msgt_name, TRUE, (ipc_object_t) port);
1170: /* object is unlocked */
1171: is_write_unlock(space);
1172:
1173: if (kr == KERN_SUCCESS)
1174: *namep = name;
1175: return kr;
1176: }
1177:
1178: /*
1179: * Routine: ipc_object_copyout_name_compat
1180: * Purpose:
1181: * Copyout a capability, placing it into a space.
1182: * The specified name is used for the capability.
1183: * If successful, consumes a ref for the object.
1184: *
1185: * Like ipc_object_copyout_name, except that
1186: * the name can't be in use at all, even for the same
1187: * port, and IE_BITS_COMPAT gets turned on.
1188: * Conditions:
1189: * Nothing locked.
1190: * Returns:
1191: * KERN_SUCCESS Copied out object, consumed ref.
1192: * KERN_INVALID_TASK The space is dead.
1193: * KERN_INVALID_CAPABILITY The object is dead.
1194: * KERN_RESOURCE_SHORTAGE No memory available.
1195: * KERN_RIGHT_EXISTS Space has rights under another name.
1196: * KERN_NAME_EXISTS Name is already used.
1197: */
1198:
1199: kern_return_t
1200: ipc_object_copyout_name_compat(space, object, msgt_name, name)
1201: ipc_space_t space;
1202: ipc_object_t object;
1203: mach_msg_type_name_t msgt_name;
1204: mach_port_t name;
1205: {
1206: ipc_entry_t entry;
1207: ipc_port_t port;
1208: kern_return_t kr;
1209:
1210: assert(IO_VALID(object));
1211: assert(io_otype(object) == IOT_PORT);
1212: port = (ipc_port_t) object;
1213:
1214: for (;;) {
1215: mach_port_t oname;
1216: ipc_entry_t oentry;
1217: ipc_port_request_index_t request;
1218:
1219: kr = ipc_entry_alloc_name(space, name, &entry);
1220: if (kr != KERN_SUCCESS)
1221: return kr;
1222: /* space is write-locked and active */
1223:
1224: if (ipc_right_inuse(space, name, entry))
1225: return KERN_NAME_EXISTS; /* space is unlocked */
1226:
1227: assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE);
1228: assert(entry->ie_object == IO_NULL);
1229:
1230: if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
1231: ipc_right_reverse(space, (ipc_object_t) port,
1232: &oname, &oentry)) {
1233: /* port is locked and active */
1234:
1235: ip_unlock(port);
1236: ipc_entry_dealloc(space, name, entry);
1237: is_write_unlock(space);
1238: return KERN_RIGHT_EXISTS;
1239: }
1240:
1241: ip_lock(port);
1242: if (!ip_active(port)) {
1243: ip_unlock(port);
1244: ipc_entry_dealloc(space, name, entry);
1245: is_write_unlock(space);
1246: return KERN_INVALID_CAPABILITY;
1247: }
1248:
1249: kr = ipc_port_dnrequest(port, name, ipr_spacem(space),
1250: &request);
1251: if (kr != KERN_SUCCESS) {
1252: ipc_entry_dealloc(space, name, entry);
1253: is_write_unlock(space);
1254:
1255: kr = ipc_port_dngrow(port);
1256: /* port is unlocked */
1257: if (kr != KERN_SUCCESS)
1258: return kr;
1259:
1260: continue;
1261: }
1262:
1263: is_reference(space); /* for dnrequest */
1264: entry->ie_object = (ipc_object_t) port;
1265: entry->ie_request = request;
1266: entry->ie_bits |= IE_BITS_COMPAT;
1267: break;
1268: }
1269:
1270: /* space is write-locked and active, port is locked and active */
1271:
1272: kr = ipc_right_copyout(space, name, entry,
1273: msgt_name, TRUE, (ipc_object_t) port);
1274: /* object is unlocked */
1275: is_write_unlock(space);
1276:
1277: assert(kr == KERN_SUCCESS);
1278: return kr;
1279: }
1280:
1281: #endif /* MACH_IPC_COMPAT */
1282:
1283: #include <mach_kdb.h>
1284:
1285:
1286: #if MACH_KDB
1287: #define printf kdbprintf
1288:
1289: /*
1290: * Routine: ipc_object_print
1291: * Purpose:
1292: * Pretty-print an object for kdb.
1293: */
1294:
1295: char *ikot_print_array[IKOT_MAX_TYPE] = {
1296: "(NONE) ",
1297: "(THREAD) ",
1298: "(TASK) ",
1299: "(HOST) ",
1300: "(HOST_PRIV) ",
1301: "(PROCESSOR) ",
1302: "(PSET) ",
1303: "(PSET_NAME) ",
1304: "(PAGER) ",
1305: "(PAGER_REQUEST) ",
1306: "(DEVICE) ", /* 10 */
1307: "(XMM_OBJECT) ",
1308: "(XMM_PAGER) ",
1309: "(XMM_KERNEL) ",
1310: "(XMM_REPLY) ",
1311: "(PAGER_TERMINATING)",
1312: "(PAGING_NAME) ",
1313: "(HOST_SECURITY) ",
1314: "(LEDGER) ",
1315: "(MASTER_DEVICE) ",
1316: "(ACTIVATION) ", /* 20 */
1317: "(SUBSYSTEM) ",
1318: "(IO_DONE_QUEUE) ",
1319: "(SEMAPHORE) ",
1320: "(LOCK_SET) ",
1321: "(CLOCK) ",
1322: "(CLOCK_CTRL) ", /* 26 */
1323: /* << new entries here */
1324: "(UNKNOWN) " /* magic catchall */
1325: }; /* Please keep in sync with kern/ipc_kobject.h */
1326:
1327: void
1328: ipc_object_print(
1329: ipc_object_t object)
1330: {
1331: int kotype;
1332:
1333: iprintf("%s", io_active(object) ? "active" : "dead");
1334: printf(", refs=%d", object->io_references);
1335: printf(", otype=%d", io_otype(object));
1336: kotype = io_kotype(object);
1337: if (kotype >= 0 && kotype < IKOT_MAX_TYPE)
1338: printf(", kotype=%d %s\n", io_kotype(object),
1339: ikot_print_array[kotype]);
1340: else
1341: printf(", kotype=0x%x %s\n", io_kotype(object),
1342: ikot_print_array[IKOT_UNKNOWN]);
1343: }
1344:
1345: #endif /* MACH_KDB */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.