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