1 | /* |
2 | * Copyright (c) 2000-2007 Apple Inc. All rights reserved. |
3 | * |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
5 | * |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License |
8 | * Version 2.0 (the 'License'). You may not use this file except in |
9 | * compliance with the License. The rights granted to you under the License |
10 | * may not be used to create, or enable the creation or redistribution of, |
11 | * unlawful or unlicensed copies of an Apple operating system, or to |
12 | * circumvent, violate, or enable the circumvention or violation of, any |
13 | * terms of an Apple operating system software license agreement. |
14 | * |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. |
17 | * |
18 | * The Original Code and all software distributed under the License are |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
23 | * Please see the License for the specific language governing rights and |
24 | * limitations under the License. |
25 | * |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
27 | */ |
28 | /* |
29 | * @OSF_COPYRIGHT@ |
30 | */ |
31 | /* |
32 | * Mach Operating System |
33 | * Copyright (c) 1991,1990,1989 Carnegie Mellon University |
34 | * All Rights Reserved. |
35 | * |
36 | * Permission to use, copy, modify and distribute this software and its |
37 | * documentation is hereby granted, provided that both the copyright |
38 | * notice and this permission notice appear in all copies of the |
39 | * software, derivative works or modified versions, and any portions |
40 | * thereof, and that both notices appear in supporting documentation. |
41 | * |
42 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" |
43 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR |
44 | * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. |
45 | * |
46 | * Carnegie Mellon requests users of this software to return to |
47 | * |
48 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU |
49 | * School of Computer Science |
50 | * Carnegie Mellon University |
51 | * Pittsburgh PA 15213-3890 |
52 | * |
53 | * any improvements or extensions that they make and grant Carnegie Mellon |
54 | * the rights to redistribute these changes. |
55 | */ |
56 | /* |
57 | * NOTICE: This file was modified by McAfee Research in 2004 to introduce |
58 | * support for mandatory and extensible security protections. This notice |
59 | * is included in support of clause 2.2 (b) of the Apple Public License, |
60 | * Version 2.0. |
61 | * Copyright (c) 2005-2006 SPARTA, Inc. |
62 | */ |
63 | /* |
64 | */ |
65 | /* |
66 | * File: ipc/ipc_object.c |
67 | * Author: Rich Draves |
68 | * Date: 1989 |
69 | * |
70 | * Functions to manipulate IPC objects. |
71 | */ |
72 | |
73 | #include <mach/mach_types.h> |
74 | #include <mach/boolean.h> |
75 | #include <mach/kern_return.h> |
76 | #include <mach/port.h> |
77 | #include <mach/message.h> |
78 | |
79 | #include <kern/kern_types.h> |
80 | #include <kern/misc_protos.h> |
81 | #include <kern/ipc_kobject.h> |
82 | |
83 | #include <ipc/ipc_types.h> |
84 | #include <ipc/ipc_importance.h> |
85 | #include <ipc/port.h> |
86 | #include <ipc/ipc_space.h> |
87 | #include <ipc/ipc_entry.h> |
88 | #include <ipc/ipc_object.h> |
89 | #include <ipc/ipc_hash.h> |
90 | #include <ipc/ipc_right.h> |
91 | #include <ipc/ipc_notify.h> |
92 | #include <ipc/ipc_port.h> |
93 | #include <ipc/ipc_pset.h> |
94 | |
95 | #include <security/mac_mach_internal.h> |
96 | |
97 | zone_t ipc_object_zones[IOT_NUMBER]; |
98 | |
99 | /* |
100 | * Routine: ipc_object_reference |
101 | * Purpose: |
102 | * Take a reference to an object. |
103 | */ |
104 | |
105 | void |
106 | ipc_object_reference( |
107 | ipc_object_t object) |
108 | { |
109 | io_reference(object); |
110 | } |
111 | |
112 | /* |
113 | * Routine: ipc_object_release |
114 | * Purpose: |
115 | * Release a reference to an object. |
116 | */ |
117 | |
118 | void |
119 | ipc_object_release( |
120 | ipc_object_t object) |
121 | { |
122 | io_release(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 Object 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 | kern_return_t |
139 | ipc_object_translate( |
140 | ipc_space_t space, |
141 | mach_port_name_t name, |
142 | mach_port_right_t right, |
143 | ipc_object_t *objectp) |
144 | { |
145 | ipc_entry_t entry; |
146 | ipc_object_t object; |
147 | kern_return_t kr; |
148 | |
149 | kr = ipc_right_lookup_read(space, name, &entry); |
150 | if (kr != KERN_SUCCESS) |
151 | return kr; |
152 | /* space is read-locked and active */ |
153 | |
154 | if ((entry->ie_bits & MACH_PORT_TYPE(right)) == MACH_PORT_TYPE_NONE) { |
155 | is_read_unlock(space); |
156 | return KERN_INVALID_RIGHT; |
157 | } |
158 | |
159 | object = entry->ie_object; |
160 | assert(object != IO_NULL); |
161 | |
162 | io_lock(object); |
163 | is_read_unlock(space); |
164 | |
165 | *objectp = object; |
166 | return KERN_SUCCESS; |
167 | } |
168 | |
169 | /* |
170 | * Routine: ipc_object_translate_two |
171 | * Purpose: |
172 | * Look up two objects in a space. |
173 | * Conditions: |
174 | * Nothing locked before. If successful, the objects |
175 | * are returned locked. The caller doesn't get a ref. |
176 | * Returns: |
177 | * KERN_SUCCESS Objects returned locked. |
178 | * KERN_INVALID_TASK The space is dead. |
179 | * KERN_INVALID_NAME A name doesn't denote a right. |
180 | * KERN_INVALID_RIGHT A name doesn't denote the correct right. |
181 | */ |
182 | |
183 | kern_return_t |
184 | ipc_object_translate_two( |
185 | ipc_space_t space, |
186 | mach_port_name_t name1, |
187 | mach_port_right_t right1, |
188 | ipc_object_t *objectp1, |
189 | mach_port_name_t name2, |
190 | mach_port_right_t right2, |
191 | ipc_object_t *objectp2) |
192 | { |
193 | ipc_entry_t entry1; |
194 | ipc_entry_t entry2; |
195 | ipc_object_t object; |
196 | kern_return_t kr; |
197 | |
198 | kr = ipc_right_lookup_two_read(space, name1, &entry1, name2, &entry2); |
199 | if (kr != KERN_SUCCESS) |
200 | return kr; |
201 | /* space is read-locked and active */ |
202 | |
203 | if ((entry1->ie_bits & MACH_PORT_TYPE(right1)) == MACH_PORT_TYPE_NONE) { |
204 | is_read_unlock(space); |
205 | mach_port_guard_exception(name1, 0, 0, kGUARD_EXC_INVALID_RIGHT); |
206 | return KERN_INVALID_RIGHT; |
207 | } |
208 | |
209 | if ((entry2->ie_bits & MACH_PORT_TYPE(right2)) == MACH_PORT_TYPE_NONE) { |
210 | is_read_unlock(space); |
211 | mach_port_guard_exception(name2, 0, 0, kGUARD_EXC_INVALID_RIGHT); |
212 | return KERN_INVALID_RIGHT; |
213 | } |
214 | |
215 | object = entry1->ie_object; |
216 | assert(object != IO_NULL); |
217 | io_lock(object); |
218 | *objectp1 = object; |
219 | |
220 | object = entry2->ie_object; |
221 | assert(object != IO_NULL); |
222 | io_lock(object); |
223 | *objectp2 = object; |
224 | |
225 | is_read_unlock(space); |
226 | return KERN_SUCCESS; |
227 | } |
228 | |
229 | /* |
230 | * Routine: ipc_object_alloc_dead |
231 | * Purpose: |
232 | * Allocate a dead-name entry. |
233 | * Conditions: |
234 | * Nothing locked. |
235 | * Returns: |
236 | * KERN_SUCCESS The dead name is allocated. |
237 | * KERN_INVALID_TASK The space is dead. |
238 | * KERN_NO_SPACE No room for an entry in the space. |
239 | * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. |
240 | */ |
241 | |
242 | kern_return_t |
243 | ipc_object_alloc_dead( |
244 | ipc_space_t space, |
245 | mach_port_name_t *namep) |
246 | { |
247 | ipc_entry_t entry; |
248 | kern_return_t kr; |
249 | |
250 | kr = ipc_entry_alloc(space, namep, &entry); |
251 | if (kr != KERN_SUCCESS) |
252 | return kr; |
253 | /* space is write-locked */ |
254 | |
255 | /* null object, MACH_PORT_TYPE_DEAD_NAME, 1 uref */ |
256 | |
257 | assert(entry->ie_object == IO_NULL); |
258 | entry->ie_bits |= MACH_PORT_TYPE_DEAD_NAME | 1; |
259 | ipc_entry_modified(space, *namep, entry); |
260 | is_write_unlock(space); |
261 | return KERN_SUCCESS; |
262 | } |
263 | |
264 | /* |
265 | * Routine: ipc_object_alloc_dead_name |
266 | * Purpose: |
267 | * Allocate a dead-name entry, with a specific name. |
268 | * Conditions: |
269 | * Nothing locked. |
270 | * Returns: |
271 | * KERN_SUCCESS The dead name is allocated. |
272 | * KERN_INVALID_TASK The space is dead. |
273 | * KERN_NAME_EXISTS The name already denotes a right. |
274 | * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. |
275 | */ |
276 | |
277 | kern_return_t |
278 | ipc_object_alloc_dead_name( |
279 | ipc_space_t space, |
280 | mach_port_name_t name) |
281 | { |
282 | ipc_entry_t entry; |
283 | kern_return_t kr; |
284 | |
285 | kr = ipc_entry_alloc_name(space, name, &entry); |
286 | if (kr != KERN_SUCCESS) |
287 | return kr; |
288 | /* space is write-locked */ |
289 | |
290 | if (ipc_right_inuse(space, name, entry)) |
291 | return KERN_NAME_EXISTS; |
292 | |
293 | /* null object, MACH_PORT_TYPE_DEAD_NAME, 1 uref */ |
294 | |
295 | assert(entry->ie_object == IO_NULL); |
296 | entry->ie_bits |= MACH_PORT_TYPE_DEAD_NAME | 1; |
297 | ipc_entry_modified(space, name, entry); |
298 | is_write_unlock(space); |
299 | return KERN_SUCCESS; |
300 | } |
301 | |
302 | /* |
303 | * Routine: ipc_object_alloc |
304 | * Purpose: |
305 | * Allocate an object. |
306 | * Conditions: |
307 | * Nothing locked. If successful, the object is returned locked. |
308 | * The space is write locked on successful return. |
309 | * The caller doesn't get a reference for the object. |
310 | * Returns: |
311 | * KERN_SUCCESS The object is allocated. |
312 | * KERN_INVALID_TASK The space is dead. |
313 | * KERN_NO_SPACE No room for an entry in the space. |
314 | * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. |
315 | */ |
316 | |
317 | kern_return_t |
318 | ipc_object_alloc( |
319 | ipc_space_t space, |
320 | ipc_object_type_t otype, |
321 | mach_port_type_t type, |
322 | mach_port_urefs_t urefs, |
323 | mach_port_name_t *namep, |
324 | ipc_object_t *objectp) |
325 | { |
326 | ipc_object_t object; |
327 | ipc_entry_t entry; |
328 | kern_return_t kr; |
329 | |
330 | assert(otype < IOT_NUMBER); |
331 | assert((type & MACH_PORT_TYPE_ALL_RIGHTS) == type); |
332 | assert(type != MACH_PORT_TYPE_NONE); |
333 | assert(urefs <= MACH_PORT_UREFS_MAX); |
334 | |
335 | object = io_alloc(otype); |
336 | if (object == IO_NULL) |
337 | return KERN_RESOURCE_SHORTAGE; |
338 | |
339 | if (otype == IOT_PORT) { |
340 | ipc_port_t port = (ipc_port_t)object; |
341 | |
342 | bzero((char *)port, sizeof(*port)); |
343 | } else if (otype == IOT_PORT_SET) { |
344 | ipc_pset_t pset = (ipc_pset_t)object; |
345 | |
346 | bzero((char *)pset, sizeof(*pset)); |
347 | } |
348 | |
349 | io_lock_init(object); |
350 | *namep = CAST_MACH_PORT_TO_NAME(object); |
351 | kr = ipc_entry_alloc(space, namep, &entry); |
352 | if (kr != KERN_SUCCESS) { |
353 | io_free(otype, object); |
354 | return kr; |
355 | } |
356 | /* space is write-locked */ |
357 | |
358 | entry->ie_bits |= type | urefs; |
359 | entry->ie_object = object; |
360 | ipc_entry_modified(space, *namep, entry); |
361 | |
362 | io_lock(object); |
363 | |
364 | object->io_references = 1; /* for entry, not caller */ |
365 | object->io_bits = io_makebits(TRUE, otype, 0); |
366 | |
367 | *objectp = object; |
368 | return KERN_SUCCESS; |
369 | } |
370 | |
371 | /* |
372 | * Routine: ipc_object_alloc_name |
373 | * Purpose: |
374 | * Allocate an object, with a specific name. |
375 | * Conditions: |
376 | * Nothing locked. If successful, the object is returned locked. |
377 | * The caller doesn't get a reference for the object. |
378 | * Returns: |
379 | * KERN_SUCCESS The object is allocated. |
380 | * KERN_INVALID_TASK The space is dead. |
381 | * KERN_NAME_EXISTS The name already denotes a right. |
382 | * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. |
383 | */ |
384 | |
385 | kern_return_t |
386 | ipc_object_alloc_name( |
387 | ipc_space_t space, |
388 | ipc_object_type_t otype, |
389 | mach_port_type_t type, |
390 | mach_port_urefs_t urefs, |
391 | mach_port_name_t name, |
392 | ipc_object_t *objectp) |
393 | { |
394 | ipc_object_t object; |
395 | ipc_entry_t entry; |
396 | kern_return_t kr; |
397 | |
398 | assert(otype < IOT_NUMBER); |
399 | assert((type & MACH_PORT_TYPE_ALL_RIGHTS) == type); |
400 | assert(type != MACH_PORT_TYPE_NONE); |
401 | assert(urefs <= MACH_PORT_UREFS_MAX); |
402 | |
403 | object = io_alloc(otype); |
404 | if (object == IO_NULL) |
405 | return KERN_RESOURCE_SHORTAGE; |
406 | |
407 | if (otype == IOT_PORT) { |
408 | ipc_port_t port = (ipc_port_t)object; |
409 | |
410 | bzero((char *)port, sizeof(*port)); |
411 | } else if (otype == IOT_PORT_SET) { |
412 | ipc_pset_t pset = (ipc_pset_t)object; |
413 | |
414 | bzero((char *)pset, sizeof(*pset)); |
415 | } |
416 | |
417 | io_lock_init(object); |
418 | kr = ipc_entry_alloc_name(space, name, &entry); |
419 | if (kr != KERN_SUCCESS) { |
420 | io_free(otype, object); |
421 | return kr; |
422 | } |
423 | /* space is write-locked */ |
424 | |
425 | if (ipc_right_inuse(space, name, entry)) { |
426 | io_free(otype, object); |
427 | return KERN_NAME_EXISTS; |
428 | } |
429 | |
430 | entry->ie_bits |= type | urefs; |
431 | entry->ie_object = object; |
432 | ipc_entry_modified(space, name, entry); |
433 | |
434 | io_lock(object); |
435 | is_write_unlock(space); |
436 | |
437 | object->io_references = 1; /* for entry, not caller */ |
438 | object->io_bits = io_makebits(TRUE, otype, 0); |
439 | |
440 | *objectp = object; |
441 | return KERN_SUCCESS; |
442 | } |
443 | |
444 | /* |
445 | * Routine: ipc_object_copyin_type |
446 | * Purpose: |
447 | * Convert a send type name to a received type name. |
448 | */ |
449 | |
450 | mach_msg_type_name_t |
451 | ipc_object_copyin_type( |
452 | mach_msg_type_name_t msgt_name) |
453 | { |
454 | switch (msgt_name) { |
455 | |
456 | case MACH_MSG_TYPE_MOVE_RECEIVE: |
457 | return MACH_MSG_TYPE_PORT_RECEIVE; |
458 | |
459 | case MACH_MSG_TYPE_MOVE_SEND_ONCE: |
460 | case MACH_MSG_TYPE_MAKE_SEND_ONCE: |
461 | return MACH_MSG_TYPE_PORT_SEND_ONCE; |
462 | |
463 | case MACH_MSG_TYPE_MOVE_SEND: |
464 | case MACH_MSG_TYPE_MAKE_SEND: |
465 | case MACH_MSG_TYPE_COPY_SEND: |
466 | return MACH_MSG_TYPE_PORT_SEND; |
467 | |
468 | case MACH_MSG_TYPE_DISPOSE_RECEIVE: |
469 | case MACH_MSG_TYPE_DISPOSE_SEND: |
470 | case MACH_MSG_TYPE_DISPOSE_SEND_ONCE: |
471 | /* fall thru */ |
472 | default: |
473 | return MACH_MSG_TYPE_PORT_NONE; |
474 | } |
475 | } |
476 | |
477 | /* |
478 | * Routine: ipc_object_copyin |
479 | * Purpose: |
480 | * Copyin a capability from a space. |
481 | * If successful, the caller gets a ref |
482 | * for the resulting object, unless it is IO_DEAD. |
483 | * Conditions: |
484 | * Nothing locked. |
485 | * Returns: |
486 | * KERN_SUCCESS Acquired an object, possibly IO_DEAD. |
487 | * KERN_INVALID_TASK The space is dead. |
488 | * KERN_INVALID_NAME Name doesn't exist in space. |
489 | * KERN_INVALID_RIGHT Name doesn't denote correct right. |
490 | */ |
491 | |
492 | kern_return_t |
493 | ipc_object_copyin( |
494 | ipc_space_t space, |
495 | mach_port_name_t name, |
496 | mach_msg_type_name_t msgt_name, |
497 | ipc_object_t *objectp) |
498 | { |
499 | ipc_entry_t entry; |
500 | ipc_port_t soright; |
501 | ipc_port_t release_port; |
502 | kern_return_t kr; |
503 | int assertcnt = 0; |
504 | |
505 | /* |
506 | * Could first try a read lock when doing |
507 | * MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND, |
508 | * and MACH_MSG_TYPE_MAKE_SEND_ONCE. |
509 | */ |
510 | |
511 | kr = ipc_right_lookup_write(space, name, &entry); |
512 | if (kr != KERN_SUCCESS) |
513 | return kr; |
514 | /* space is write-locked and active */ |
515 | |
516 | release_port = IP_NULL; |
517 | kr = ipc_right_copyin(space, name, entry, |
518 | msgt_name, TRUE, |
519 | objectp, &soright, |
520 | &release_port, |
521 | &assertcnt); |
522 | if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE) |
523 | ipc_entry_dealloc(space, name, entry); |
524 | is_write_unlock(space); |
525 | |
526 | #if IMPORTANCE_INHERITANCE |
527 | if (0 < assertcnt && ipc_importance_task_is_any_receiver_type(current_task()->task_imp_base)) { |
528 | ipc_importance_task_drop_internal_assertion(current_task()->task_imp_base, assertcnt); |
529 | } |
530 | #endif /* IMPORTANCE_INHERITANCE */ |
531 | |
532 | if (release_port != IP_NULL) |
533 | ip_release(release_port); |
534 | |
535 | if ((kr == KERN_SUCCESS) && (soright != IP_NULL)) |
536 | ipc_notify_port_deleted(soright, name); |
537 | |
538 | return kr; |
539 | } |
540 | |
541 | /* |
542 | * Routine: ipc_object_copyin_from_kernel |
543 | * Purpose: |
544 | * Copyin a naked capability from the kernel. |
545 | * |
546 | * MACH_MSG_TYPE_MOVE_RECEIVE |
547 | * The receiver must be ipc_space_kernel |
548 | * or the receive right must already be in limbo. |
549 | * Consumes the naked receive right. |
550 | * MACH_MSG_TYPE_COPY_SEND |
551 | * A naked send right must be supplied. |
552 | * The port gains a reference, and a send right |
553 | * if the port is still active. |
554 | * MACH_MSG_TYPE_MAKE_SEND |
555 | * The receiver must be ipc_space_kernel. |
556 | * The port gains a reference and a send right. |
557 | * MACH_MSG_TYPE_MOVE_SEND |
558 | * Consumes a naked send right. |
559 | * MACH_MSG_TYPE_MAKE_SEND_ONCE |
560 | * The port gains a reference and a send-once right. |
561 | * Receiver also be the caller of device subsystem, |
562 | * so no assertion. |
563 | * MACH_MSG_TYPE_MOVE_SEND_ONCE |
564 | * Consumes a naked send-once right. |
565 | * Conditions: |
566 | * Nothing locked. |
567 | */ |
568 | |
569 | void |
570 | ipc_object_copyin_from_kernel( |
571 | ipc_object_t object, |
572 | mach_msg_type_name_t msgt_name) |
573 | { |
574 | assert(IO_VALID(object)); |
575 | |
576 | switch (msgt_name) { |
577 | case MACH_MSG_TYPE_MOVE_RECEIVE: { |
578 | ipc_port_t port = (ipc_port_t) object; |
579 | |
580 | ip_lock(port); |
581 | imq_lock(&port->ip_messages); |
582 | assert(ip_active(port)); |
583 | if (port->ip_destination != IP_NULL) { |
584 | assert(port->ip_receiver == ipc_space_kernel); |
585 | |
586 | /* relevant part of ipc_port_clear_receiver */ |
587 | ipc_port_set_mscount(port, 0); |
588 | |
589 | port->ip_receiver_name = MACH_PORT_NULL; |
590 | port->ip_destination = IP_NULL; |
591 | } |
592 | imq_unlock(&port->ip_messages); |
593 | ip_unlock(port); |
594 | break; |
595 | } |
596 | |
597 | case MACH_MSG_TYPE_COPY_SEND: { |
598 | ipc_port_t port = (ipc_port_t) object; |
599 | |
600 | ip_lock(port); |
601 | if (ip_active(port)) { |
602 | assert(port->ip_srights > 0); |
603 | port->ip_srights++; |
604 | } |
605 | ip_reference(port); |
606 | ip_unlock(port); |
607 | break; |
608 | } |
609 | |
610 | case MACH_MSG_TYPE_MAKE_SEND: { |
611 | ipc_port_t port = (ipc_port_t) object; |
612 | |
613 | ip_lock(port); |
614 | if (ip_active(port)) { |
615 | assert(port->ip_receiver_name != MACH_PORT_NULL); |
616 | assert((port->ip_receiver == ipc_space_kernel) || |
617 | (port->ip_receiver->is_node_id != HOST_LOCAL_NODE)); |
618 | port->ip_mscount++; |
619 | } |
620 | |
621 | port->ip_srights++; |
622 | ip_reference(port); |
623 | ip_unlock(port); |
624 | break; |
625 | } |
626 | |
627 | case MACH_MSG_TYPE_MOVE_SEND: { |
628 | /* move naked send right into the message */ |
629 | assert(((ipc_port_t)object)->ip_srights); |
630 | break; |
631 | } |
632 | |
633 | case MACH_MSG_TYPE_MAKE_SEND_ONCE: { |
634 | ipc_port_t port = (ipc_port_t) object; |
635 | |
636 | ip_lock(port); |
637 | if (ip_active(port)) { |
638 | assert(port->ip_receiver_name != MACH_PORT_NULL); |
639 | } |
640 | port->ip_sorights++; |
641 | ip_reference(port); |
642 | ip_unlock(port); |
643 | break; |
644 | } |
645 | |
646 | case MACH_MSG_TYPE_MOVE_SEND_ONCE: { |
647 | /* move naked send-once right into the message */ |
648 | assert(((ipc_port_t)object)->ip_sorights); |
649 | break; |
650 | } |
651 | |
652 | default: |
653 | panic("ipc_object_copyin_from_kernel: strange rights" ); |
654 | } |
655 | } |
656 | |
657 | /* |
658 | * Routine: ipc_object_destroy |
659 | * Purpose: |
660 | * Destroys a naked capability. |
661 | * Consumes a ref for the object. |
662 | * |
663 | * A receive right should be in limbo or in transit. |
664 | * Conditions: |
665 | * Nothing locked. |
666 | */ |
667 | |
668 | void |
669 | ipc_object_destroy( |
670 | ipc_object_t object, |
671 | mach_msg_type_name_t msgt_name) |
672 | { |
673 | assert(IO_VALID(object)); |
674 | assert(io_otype(object) == IOT_PORT); |
675 | |
676 | switch (msgt_name) { |
677 | case MACH_MSG_TYPE_PORT_SEND: |
678 | ipc_port_release_send((ipc_port_t) object); |
679 | break; |
680 | |
681 | case MACH_MSG_TYPE_PORT_SEND_ONCE: |
682 | ipc_notify_send_once((ipc_port_t) object); |
683 | break; |
684 | |
685 | case MACH_MSG_TYPE_PORT_RECEIVE: |
686 | ipc_port_release_receive((ipc_port_t) object); |
687 | break; |
688 | |
689 | default: |
690 | panic("ipc_object_destroy: strange rights" ); |
691 | } |
692 | } |
693 | |
694 | /* |
695 | * Routine: ipc_object_destroy_dest |
696 | * Purpose: |
697 | * Destroys a naked capability for the destination of |
698 | * of a message. Consumes a ref for the object. |
699 | * |
700 | * Conditions: |
701 | * Nothing locked. |
702 | */ |
703 | |
704 | void |
705 | ipc_object_destroy_dest( |
706 | ipc_object_t object, |
707 | mach_msg_type_name_t msgt_name) |
708 | { |
709 | assert(IO_VALID(object)); |
710 | assert(io_otype(object) == IOT_PORT); |
711 | |
712 | switch (msgt_name) { |
713 | case MACH_MSG_TYPE_PORT_SEND: |
714 | ipc_port_release_send((ipc_port_t) object); |
715 | break; |
716 | |
717 | case MACH_MSG_TYPE_PORT_SEND_ONCE: |
718 | if (io_active(object) && |
719 | !ip_full_kernel((ipc_port_t) object)) |
720 | ipc_notify_send_once((ipc_port_t) object); |
721 | else |
722 | ipc_port_release_sonce((ipc_port_t) object); |
723 | break; |
724 | |
725 | default: |
726 | panic("ipc_object_destroy_dest: strange rights" ); |
727 | } |
728 | } |
729 | |
730 | /* |
731 | * Routine: ipc_object_copyout |
732 | * Purpose: |
733 | * Copyout a capability, placing it into a space. |
734 | * If successful, consumes a ref for the object. |
735 | * Conditions: |
736 | * Nothing locked. |
737 | * Returns: |
738 | * KERN_SUCCESS Copied out object, consumed ref. |
739 | * KERN_INVALID_TASK The space is dead. |
740 | * KERN_INVALID_CAPABILITY The object is dead. |
741 | * KERN_NO_SPACE No room in space for another right. |
742 | * KERN_RESOURCE_SHORTAGE No memory available. |
743 | * KERN_UREFS_OVERFLOW Urefs limit exceeded |
744 | * and overflow wasn't specified. |
745 | */ |
746 | |
747 | kern_return_t |
748 | ipc_object_copyout( |
749 | ipc_space_t space, |
750 | ipc_object_t object, |
751 | mach_msg_type_name_t msgt_name, |
752 | boolean_t overflow, |
753 | mach_port_name_t *namep) |
754 | { |
755 | struct knote *kn = current_thread()->ith_knote; |
756 | mach_port_name_t name; |
757 | ipc_entry_t entry; |
758 | kern_return_t kr; |
759 | |
760 | assert(IO_VALID(object)); |
761 | assert(io_otype(object) == IOT_PORT); |
762 | |
763 | if (ITH_KNOTE_VALID(kn, msgt_name)) { |
764 | filt_machport_turnstile_prepare_lazily(kn, |
765 | msgt_name, (ipc_port_t)object); |
766 | } |
767 | |
768 | is_write_lock(space); |
769 | |
770 | for (;;) { |
771 | if (!is_active(space)) { |
772 | is_write_unlock(space); |
773 | return KERN_INVALID_TASK; |
774 | } |
775 | |
776 | if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) && |
777 | ipc_right_reverse(space, object, &name, &entry)) { |
778 | /* object is locked and active */ |
779 | |
780 | assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE); |
781 | break; |
782 | } |
783 | |
784 | name = CAST_MACH_PORT_TO_NAME(object); |
785 | kr = ipc_entry_get(space, &name, &entry); |
786 | if (kr != KERN_SUCCESS) { |
787 | /* unlocks/locks space, so must start again */ |
788 | |
789 | kr = ipc_entry_grow_table(space, ITS_SIZE_NONE); |
790 | if (kr != KERN_SUCCESS) |
791 | return kr; /* space is unlocked */ |
792 | |
793 | continue; |
794 | } |
795 | |
796 | assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE); |
797 | assert(entry->ie_object == IO_NULL); |
798 | |
799 | io_lock(object); |
800 | if (!io_active(object)) { |
801 | io_unlock(object); |
802 | ipc_entry_dealloc(space, name, entry); |
803 | is_write_unlock(space); |
804 | return KERN_INVALID_CAPABILITY; |
805 | } |
806 | |
807 | entry->ie_object = object; |
808 | break; |
809 | } |
810 | |
811 | /* space is write-locked and active, object is locked and active */ |
812 | |
813 | kr = ipc_right_copyout(space, name, entry, |
814 | msgt_name, overflow, object); |
815 | |
816 | /* object is unlocked */ |
817 | is_write_unlock(space); |
818 | |
819 | if (kr == KERN_SUCCESS) |
820 | *namep = name; |
821 | return kr; |
822 | } |
823 | |
824 | /* |
825 | * Routine: ipc_object_copyout_name |
826 | * Purpose: |
827 | * Copyout a capability, placing it into a space. |
828 | * The specified name is used for the capability. |
829 | * If successful, consumes a ref for the object. |
830 | * Conditions: |
831 | * Nothing locked. |
832 | * Returns: |
833 | * KERN_SUCCESS Copied out object, consumed ref. |
834 | * KERN_INVALID_TASK The space is dead. |
835 | * KERN_INVALID_CAPABILITY The object is dead. |
836 | * KERN_RESOURCE_SHORTAGE No memory available. |
837 | * KERN_UREFS_OVERFLOW Urefs limit exceeded |
838 | * and overflow wasn't specified. |
839 | * KERN_RIGHT_EXISTS Space has rights under another name. |
840 | * KERN_NAME_EXISTS Name is already used. |
841 | */ |
842 | |
843 | kern_return_t |
844 | ipc_object_copyout_name( |
845 | ipc_space_t space, |
846 | ipc_object_t object, |
847 | mach_msg_type_name_t msgt_name, |
848 | boolean_t overflow, |
849 | mach_port_name_t name) |
850 | { |
851 | mach_port_name_t oname; |
852 | ipc_entry_t oentry; |
853 | ipc_entry_t entry; |
854 | kern_return_t kr; |
855 | struct knote *kn = current_thread()->ith_knote; |
856 | |
857 | #if IMPORTANCE_INHERITANCE |
858 | int assertcnt = 0; |
859 | ipc_importance_task_t task_imp = IIT_NULL; |
860 | #endif /* IMPORTANCE_INHERITANCE */ |
861 | |
862 | assert(IO_VALID(object)); |
863 | assert(io_otype(object) == IOT_PORT); |
864 | |
865 | if (ITH_KNOTE_VALID(kn, msgt_name)) { |
866 | filt_machport_turnstile_prepare_lazily(kn, |
867 | msgt_name, (ipc_port_t)object); |
868 | } |
869 | |
870 | kr = ipc_entry_alloc_name(space, name, &entry); |
871 | if (kr != KERN_SUCCESS) |
872 | return kr; |
873 | /* space is write-locked and active */ |
874 | |
875 | if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) && |
876 | ipc_right_reverse(space, object, &oname, &oentry)) { |
877 | /* object is locked and active */ |
878 | |
879 | if (name != oname) { |
880 | io_unlock(object); |
881 | |
882 | if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE) |
883 | ipc_entry_dealloc(space, name, entry); |
884 | |
885 | is_write_unlock(space); |
886 | return KERN_RIGHT_EXISTS; |
887 | } |
888 | |
889 | assert(entry == oentry); |
890 | assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE); |
891 | } else { |
892 | if (ipc_right_inuse(space, name, entry)) |
893 | return KERN_NAME_EXISTS; |
894 | |
895 | assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE); |
896 | assert(entry->ie_object == IO_NULL); |
897 | |
898 | io_lock(object); |
899 | if (!io_active(object)) { |
900 | io_unlock(object); |
901 | ipc_entry_dealloc(space, name, entry); |
902 | is_write_unlock(space); |
903 | return KERN_INVALID_CAPABILITY; |
904 | } |
905 | |
906 | entry->ie_object = object; |
907 | } |
908 | |
909 | /* space is write-locked and active, object is locked and active */ |
910 | |
911 | #if IMPORTANCE_INHERITANCE |
912 | /* |
913 | * We are slamming a receive right into the space, without |
914 | * first having been enqueued on a port destined there. So, |
915 | * we have to arrange to boost the task appropriately if this |
916 | * port has assertions (and the task wants them). |
917 | */ |
918 | if (msgt_name == MACH_MSG_TYPE_PORT_RECEIVE) { |
919 | ipc_port_t port = (ipc_port_t)object; |
920 | |
921 | if (space->is_task != TASK_NULL) { |
922 | task_imp = space->is_task->task_imp_base; |
923 | if (ipc_importance_task_is_any_receiver_type(task_imp)) { |
924 | assertcnt = port->ip_impcount; |
925 | ipc_importance_task_reference(task_imp); |
926 | } else { |
927 | task_imp = IIT_NULL; |
928 | } |
929 | } |
930 | |
931 | /* take port out of limbo */ |
932 | assert(port->ip_tempowner != 0); |
933 | port->ip_tempowner = 0; |
934 | } |
935 | |
936 | #endif /* IMPORTANCE_INHERITANCE */ |
937 | |
938 | kr = ipc_right_copyout(space, name, entry, |
939 | msgt_name, overflow, object); |
940 | |
941 | /* object is unlocked */ |
942 | is_write_unlock(space); |
943 | |
944 | #if IMPORTANCE_INHERITANCE |
945 | /* |
946 | * Add the assertions to the task that we captured before |
947 | */ |
948 | if (task_imp != IIT_NULL) { |
949 | ipc_importance_task_hold_internal_assertion(task_imp, assertcnt); |
950 | ipc_importance_task_release(task_imp); |
951 | } |
952 | #endif /* IMPORTANCE_INHERITANCE */ |
953 | |
954 | return kr; |
955 | } |
956 | |
957 | /* |
958 | * Routine: ipc_object_copyout_dest |
959 | * Purpose: |
960 | * Translates/consumes the destination right of a message. |
961 | * This is unlike normal copyout because the right is consumed |
962 | * in a funny way instead of being given to the receiving space. |
963 | * The receiver gets his name for the port, if he has receive |
964 | * rights, otherwise MACH_PORT_NULL. |
965 | * Conditions: |
966 | * The object is locked and active. Nothing else locked. |
967 | * The object is unlocked and loses a reference. |
968 | */ |
969 | |
970 | void |
971 | ipc_object_copyout_dest( |
972 | ipc_space_t space, |
973 | ipc_object_t object, |
974 | mach_msg_type_name_t msgt_name, |
975 | mach_port_name_t *namep) |
976 | { |
977 | mach_port_name_t name; |
978 | |
979 | assert(IO_VALID(object)); |
980 | assert(io_active(object)); |
981 | |
982 | io_release(object); |
983 | |
984 | /* |
985 | * If the space is the receiver/owner of the object, |
986 | * then we quietly consume the right and return |
987 | * the space's name for the object. Otherwise |
988 | * we destroy the right and return MACH_PORT_NULL. |
989 | */ |
990 | |
991 | switch (msgt_name) { |
992 | case MACH_MSG_TYPE_PORT_SEND: { |
993 | ipc_port_t port = (ipc_port_t) object; |
994 | ipc_port_t nsrequest = IP_NULL; |
995 | mach_port_mscount_t mscount; |
996 | |
997 | if (port->ip_receiver == space) |
998 | name = port->ip_receiver_name; |
999 | else |
1000 | name = MACH_PORT_NULL; |
1001 | |
1002 | assert(port->ip_srights > 0); |
1003 | if (--port->ip_srights == 0 && |
1004 | port->ip_nsrequest != IP_NULL) { |
1005 | nsrequest = port->ip_nsrequest; |
1006 | port->ip_nsrequest = IP_NULL; |
1007 | mscount = port->ip_mscount; |
1008 | ip_unlock(port); |
1009 | ipc_notify_no_senders(nsrequest, mscount); |
1010 | } else |
1011 | ip_unlock(port); |
1012 | break; |
1013 | } |
1014 | |
1015 | case MACH_MSG_TYPE_PORT_SEND_ONCE: { |
1016 | ipc_port_t port = (ipc_port_t) object; |
1017 | |
1018 | assert(port->ip_sorights > 0); |
1019 | |
1020 | if (port->ip_receiver == space) { |
1021 | /* quietly consume the send-once right */ |
1022 | |
1023 | port->ip_sorights--; |
1024 | name = port->ip_receiver_name; |
1025 | ip_unlock(port); |
1026 | } else { |
1027 | /* |
1028 | * A very bizarre case. The message |
1029 | * was received, but before this copyout |
1030 | * happened the space lost receive rights. |
1031 | * We can't quietly consume the soright |
1032 | * out from underneath some other task, |
1033 | * so generate a send-once notification. |
1034 | */ |
1035 | |
1036 | ip_reference(port); /* restore ref */ |
1037 | ip_unlock(port); |
1038 | |
1039 | ipc_notify_send_once(port); |
1040 | name = MACH_PORT_NULL; |
1041 | } |
1042 | |
1043 | break; |
1044 | } |
1045 | |
1046 | default: |
1047 | panic("ipc_object_copyout_dest: strange rights" ); |
1048 | name = MACH_PORT_DEAD; |
1049 | } |
1050 | |
1051 | *namep = name; |
1052 | } |
1053 | |
1054 | /* |
1055 | * Routine: ipc_object_rename |
1056 | * Purpose: |
1057 | * Rename an entry in a space. |
1058 | * Conditions: |
1059 | * Nothing locked. |
1060 | * Returns: |
1061 | * KERN_SUCCESS Renamed the entry. |
1062 | * KERN_INVALID_TASK The space was dead. |
1063 | * KERN_INVALID_NAME oname didn't denote an entry. |
1064 | * KERN_NAME_EXISTS nname already denoted an entry. |
1065 | * KERN_RESOURCE_SHORTAGE Couldn't allocate new entry. |
1066 | */ |
1067 | |
1068 | kern_return_t |
1069 | ipc_object_rename( |
1070 | ipc_space_t space, |
1071 | mach_port_name_t oname, |
1072 | mach_port_name_t nname) |
1073 | { |
1074 | ipc_entry_t oentry, nentry; |
1075 | kern_return_t kr; |
1076 | |
1077 | kr = ipc_entry_alloc_name(space, nname, &nentry); |
1078 | if (kr != KERN_SUCCESS) |
1079 | return kr; |
1080 | |
1081 | /* space is write-locked and active */ |
1082 | |
1083 | if (ipc_right_inuse(space, nname, nentry)) { |
1084 | /* space is unlocked */ |
1085 | return KERN_NAME_EXISTS; |
1086 | } |
1087 | |
1088 | /* don't let ipc_entry_lookup see the uninitialized new entry */ |
1089 | |
1090 | if ((oname == nname) || |
1091 | ((oentry = ipc_entry_lookup(space, oname)) == IE_NULL)) { |
1092 | ipc_entry_dealloc(space, nname, nentry); |
1093 | is_write_unlock(space); |
1094 | return KERN_INVALID_NAME; |
1095 | } |
1096 | |
1097 | kr = ipc_right_rename(space, oname, oentry, nname, nentry); |
1098 | /* space is unlocked */ |
1099 | return kr; |
1100 | } |
1101 | |
1102 | /* |
1103 | * Check whether the object is a port if so, free it. But |
1104 | * keep track of that fact. |
1105 | */ |
1106 | void |
1107 | io_free( |
1108 | unsigned int otype, |
1109 | ipc_object_t object) |
1110 | { |
1111 | ipc_port_t port; |
1112 | |
1113 | if (otype == IOT_PORT) { |
1114 | port = (ipc_port_t) object; |
1115 | ipc_port_finalize(port); |
1116 | } |
1117 | io_lock_destroy(object); |
1118 | zfree(ipc_object_zones[otype], object); |
1119 | } |
1120 | |