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