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