xref: /xnu-8020.140.41/osfmk/ipc/mach_debug.c (revision 27b03b360a988dfd3dfdf34262bb0042026747cc)
1 /*
2  * Copyright (c) 2000-2004 Apple Computer, 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 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  [email protected]
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  */
58 /*
59  *	File:	ipc/mach_debug.c
60  *	Author:	Rich Draves
61  *	Date:	1989
62  *
63  *	Exported IPC debug calls.
64  */
65 #include <mach_ipc_debug.h>
66 
67 #include <mach/vm_param.h>
68 #include <mach/kern_return.h>
69 #include <mach/machine/vm_types.h>
70 #include <mach/mach_host_server.h>
71 #include <mach/mach_port_server.h>
72 #include <mach_debug/ipc_info.h>
73 #include <mach_debug/hash_info.h>
74 
75 #if MACH_IPC_DEBUG
76 #include <kern/host.h>
77 #include <kern/misc_protos.h>
78 #include <vm/vm_map.h>
79 #include <vm/vm_kern.h>
80 #include <ipc/port.h>
81 #include <ipc/ipc_types.h>
82 #include <ipc/ipc_space.h>
83 #include <ipc/ipc_port.h>
84 #include <ipc/ipc_hash.h>
85 #include <ipc/ipc_table.h>
86 #include <ipc/ipc_right.h>
87 
88 #include <security/mac_mach_internal.h>
89 #include <device/device_types.h>
90 #endif
91 
92 /*
93  *	Routine:	mach_port_get_srights [kernel call]
94  *	Purpose:
95  *		Retrieve the number of extant send rights
96  *		that a receive right has.
97  *	Conditions:
98  *		Nothing locked.
99  *	Returns:
100  *		KERN_SUCCESS		Retrieved number of send rights.
101  *		KERN_INVALID_TASK	The space is null.
102  *		KERN_INVALID_TASK	The space is dead.
103  *		KERN_INVALID_NAME	The name doesn't denote a right.
104  *		KERN_INVALID_RIGHT	Name doesn't denote receive rights.
105  */
106 
107 #if !MACH_IPC_DEBUG
108 kern_return_t
mach_port_get_srights(__unused ipc_space_t space,__unused mach_port_name_t name,__unused mach_port_rights_t * srightsp)109 mach_port_get_srights(
110 	__unused ipc_space_t            space,
111 	__unused mach_port_name_t       name,
112 	__unused mach_port_rights_t     *srightsp)
113 {
114 	return KERN_FAILURE;
115 }
116 #else
117 kern_return_t
mach_port_get_srights(ipc_space_t space,mach_port_name_t name,mach_port_rights_t * srightsp)118 mach_port_get_srights(
119 	ipc_space_t             space,
120 	mach_port_name_t        name,
121 	mach_port_rights_t      *srightsp)
122 {
123 	ipc_port_t port;
124 	kern_return_t kr;
125 	mach_port_rights_t srights;
126 
127 	if (space == IS_NULL) {
128 		return KERN_INVALID_TASK;
129 	}
130 
131 	kr = ipc_port_translate_receive(space, name, &port);
132 	if (kr != KERN_SUCCESS) {
133 		return kr;
134 	}
135 	/* port is locked and active */
136 
137 	srights = port->ip_srights;
138 	ip_mq_unlock(port);
139 
140 	*srightsp = srights;
141 	return KERN_SUCCESS;
142 }
143 #endif /* MACH_IPC_DEBUG */
144 
145 
146 /*
147  *	Routine:	mach_port_space_info
148  *	Purpose:
149  *		Returns information about an IPC space.
150  *	Conditions:
151  *		Nothing locked.  Obeys CountInOut protocol.
152  *	Returns:
153  *		KERN_SUCCESS		Returned information.
154  *		KERN_INVALID_TASK	The space is null.
155  *		KERN_INVALID_TASK	The space is dead.
156  *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
157  */
158 
159 #if !MACH_IPC_DEBUG
160 kern_return_t
mach_port_space_info_from_user(__unused mach_port_t port,__unused ipc_info_space_t * infop,__unused ipc_info_name_array_t * tablep,__unused mach_msg_type_number_t * tableCntp,__unused ipc_info_tree_name_array_t * treep,__unused mach_msg_type_number_t * treeCntp)161 mach_port_space_info_from_user(
162 	__unused mach_port_t                    port,
163 	__unused ipc_info_space_t               *infop,
164 	__unused ipc_info_name_array_t  *tablep,
165 	__unused mach_msg_type_number_t         *tableCntp,
166 	__unused ipc_info_tree_name_array_t *treep,
167 	__unused mach_msg_type_number_t         *treeCntp)
168 {
169 	return KERN_FAILURE;
170 }
171 
172 #else
173 kern_return_t
174 mach_port_space_info(
175 	ipc_space_t                     space,
176 	ipc_info_space_t                *infop,
177 	ipc_info_name_array_t           *tablep,
178 	mach_msg_type_number_t          *tableCntp,
179 	__unused ipc_info_tree_name_array_t     *treep,
180 	__unused mach_msg_type_number_t         *treeCntp);
181 
182 kern_return_t
mach_port_space_info(ipc_space_t space,ipc_info_space_t * infop,ipc_info_name_array_t * tablep,mach_msg_type_number_t * tableCntp,__unused ipc_info_tree_name_array_t * treep,__unused mach_msg_type_number_t * treeCntp)183 mach_port_space_info(
184 	ipc_space_t                     space,
185 	ipc_info_space_t                *infop,
186 	ipc_info_name_array_t           *tablep,
187 	mach_msg_type_number_t          *tableCntp,
188 	__unused ipc_info_tree_name_array_t     *treep,
189 	__unused mach_msg_type_number_t         *treeCntp)
190 {
191 	const uint32_t BATCH_SIZE = 4 << 10;
192 	ipc_info_name_t *table_info;
193 	vm_offset_t table_addr = 0;
194 	vm_size_t table_size, table_size_needed;
195 	ipc_entry_t table;
196 	ipc_entry_num_t tsize;
197 	kern_return_t kr;
198 	vm_map_copy_t copy;
199 
200 	if (space == IS_NULL) {
201 		return KERN_INVALID_TASK;
202 	}
203 
204 #if !(DEVELOPMENT || DEBUG) && CONFIG_MACF
205 	const boolean_t dbg_ok = (mac_task_check_expose_task(kernel_task, TASK_FLAVOR_CONTROL) == 0);
206 #else
207 	const boolean_t dbg_ok = TRUE;
208 #endif
209 
210 	/* start with in-line memory */
211 
212 	table_size = 0;
213 
214 	is_read_lock(space);
215 
216 allocate_loop:
217 	for (;;) {
218 		if (!is_active(space)) {
219 			is_read_unlock(space);
220 			if (table_size != 0) {
221 				kmem_free(ipc_kernel_map,
222 				    table_addr, table_size);
223 			}
224 			return KERN_INVALID_TASK;
225 		}
226 
227 		table = is_active_table(space);
228 		tsize = table->ie_size;
229 
230 		table_size_needed =
231 		    vm_map_round_page(tsize * sizeof(ipc_info_name_t),
232 		    VM_MAP_PAGE_MASK(ipc_kernel_map));
233 
234 		if (table_size_needed <= table_size) {
235 			break;
236 		}
237 
238 		is_read_unlock(space);
239 
240 		if (table_size != 0) {
241 			kmem_free(ipc_kernel_map, table_addr, table_size);
242 		}
243 		kr = kmem_alloc(ipc_kernel_map, &table_addr, table_size_needed,
244 		    KMA_DATA, VM_KERN_MEMORY_IPC);
245 		if (kr != KERN_SUCCESS) {
246 			return KERN_RESOURCE_SHORTAGE;
247 		}
248 		table_size = table_size_needed;
249 
250 		is_read_lock(space);
251 	}
252 	/* space is read-locked and active; we have enough wired memory */
253 
254 	/* walk the table for this space */
255 	table_info = (ipc_info_name_array_t)table_addr;
256 	for (mach_port_index_t index = 0; index < tsize; index++) {
257 		ipc_info_name_t *iin = &table_info[index];
258 		ipc_entry_t entry = &table[index];
259 		ipc_entry_bits_t bits;
260 
261 		if (index == 0) {
262 			bits = IE_BITS_GEN_MASK;
263 		} else {
264 			bits = entry->ie_bits;
265 		}
266 		iin->iin_name = MACH_PORT_MAKE(index, IE_BITS_GEN(bits));
267 		iin->iin_collision = 0;
268 		iin->iin_type = IE_BITS_TYPE(bits);
269 		if ((bits & MACH_PORT_TYPE_PORT_RIGHTS) != MACH_PORT_TYPE_NONE &&
270 		    entry->ie_request != IE_REQ_NONE) {
271 			ipc_port_t port = ip_object_to_port(entry->ie_object);
272 
273 			assert(IP_VALID(port));
274 			ip_mq_lock(port);
275 			iin->iin_type |= ipc_port_request_type(port, iin->iin_name, entry->ie_request);
276 			ip_mq_unlock(port);
277 		}
278 
279 		iin->iin_urefs = IE_BITS_UREFS(bits);
280 		iin->iin_object = (dbg_ok) ? (natural_t)VM_KERNEL_ADDRPERM((uintptr_t)entry->ie_object) : 0;
281 		iin->iin_next = entry->ie_next;
282 		iin->iin_hash = entry->ie_index;
283 
284 		if (index + 1 < tsize && (index + 1) % BATCH_SIZE == 0) {
285 			/*
286 			 * Give the system some breathing room,
287 			 * and check if anything changed,
288 			 * if yes start over.
289 			 */
290 			is_read_unlock(space);
291 			is_read_lock(space);
292 			if (!is_active(space)) {
293 				goto allocate_loop;
294 			}
295 			table = is_active_table(space);
296 			if (tsize < table->ie_size) {
297 				goto allocate_loop;
298 			}
299 			tsize = table->ie_size;
300 		}
301 	}
302 
303 	/* get the overall space info */
304 	infop->iis_genno_mask = MACH_PORT_NGEN(MACH_PORT_DEAD);
305 	infop->iis_table_size = tsize;
306 	infop->iis_table_next = space->is_table_next->its_size;
307 
308 	is_read_unlock(space);
309 
310 	/* prepare the table out-of-line data for return */
311 	if (table_size > 0) {
312 		vm_map_size_t used = tsize * sizeof(ipc_info_name_t);
313 		vm_map_size_t keep = vm_map_round_page(used,
314 		    VM_MAP_PAGE_MASK(ipc_kernel_map));
315 
316 		if (keep < table_size) {
317 			kmem_free(ipc_kernel_map, table_addr + keep,
318 			    table_size - keep);
319 			table_size = keep;
320 		}
321 		if (table_size > used) {
322 			bzero(&table_info[infop->iis_table_size],
323 			    table_size - used);
324 		}
325 
326 		kr = vm_map_unwire(ipc_kernel_map, table_addr,
327 		    table_addr + table_size, FALSE);
328 		assert(kr == KERN_SUCCESS);
329 		kr = vm_map_copyin(ipc_kernel_map, table_addr, used, TRUE, &copy);
330 		assert(kr == KERN_SUCCESS);
331 		*tablep = (ipc_info_name_t *)copy;
332 		*tableCntp = infop->iis_table_size;
333 	} else {
334 		*tablep = (ipc_info_name_t *)0;
335 		*tableCntp = 0;
336 	}
337 
338 	/* splay tree is obsolete, no work to do... */
339 	*treep = (ipc_info_tree_name_t *)0;
340 	*treeCntp = 0;
341 	return KERN_SUCCESS;
342 }
343 
344 kern_return_t
mach_port_space_info_from_user(mach_port_t port,ipc_info_space_t * infop,ipc_info_name_array_t * tablep,mach_msg_type_number_t * tableCntp,__unused ipc_info_tree_name_array_t * treep,__unused mach_msg_type_number_t * treeCntp)345 mach_port_space_info_from_user(
346 	mach_port_t                     port,
347 	ipc_info_space_t                *infop,
348 	ipc_info_name_array_t           *tablep,
349 	mach_msg_type_number_t          *tableCntp,
350 	__unused ipc_info_tree_name_array_t     *treep,
351 	__unused mach_msg_type_number_t         *treeCntp)
352 {
353 	kern_return_t kr;
354 
355 	ipc_space_t space = convert_port_to_space_read_no_eval(port);
356 
357 	if (space == IPC_SPACE_NULL) {
358 		return KERN_INVALID_ARGUMENT;
359 	}
360 
361 	kr = mach_port_space_info(space, infop, tablep, tableCntp, treep, treeCntp);
362 
363 	ipc_space_release(space);
364 	return kr;
365 }
366 #endif /* MACH_IPC_DEBUG */
367 
368 /*
369  *	Routine:	mach_port_space_basic_info
370  *	Purpose:
371  *		Returns basic information about an IPC space.
372  *	Conditions:
373  *		Nothing locked.
374  *	Returns:
375  *		KERN_SUCCESS		Returned information.
376  *		KERN_FAILURE		The call is not supported.
377  *		KERN_INVALID_TASK	The space is dead.
378  */
379 
380 #if !MACH_IPC_DEBUG
381 kern_return_t
mach_port_space_basic_info(__unused ipc_space_t space,__unused ipc_info_space_basic_t * infop)382 mach_port_space_basic_info(
383 	__unused ipc_space_t                    space,
384 	__unused ipc_info_space_basic_t         *infop)
385 {
386 	return KERN_FAILURE;
387 }
388 #else
389 kern_return_t
mach_port_space_basic_info(ipc_space_t space,ipc_info_space_basic_t * infop)390 mach_port_space_basic_info(
391 	ipc_space_t                     space,
392 	ipc_info_space_basic_t          *infop)
393 {
394 	ipc_entry_num_t tsize;
395 
396 	if (space == IS_NULL) {
397 		return KERN_INVALID_TASK;
398 	}
399 
400 	is_read_lock(space);
401 	if (!is_active(space)) {
402 		is_read_unlock(space);
403 		return KERN_INVALID_TASK;
404 	}
405 
406 	tsize = is_active_table(space)->ie_size;
407 
408 	/* get the basic space info */
409 	infop->iisb_genno_mask = MACH_PORT_NGEN(MACH_PORT_DEAD);
410 	infop->iisb_table_size = tsize;
411 	infop->iisb_table_next = space->is_table_next->its_size;
412 	infop->iisb_table_inuse = tsize - space->is_table_free - 1;
413 	infop->iisb_reserved[0] = 0;
414 	infop->iisb_reserved[1] = 0;
415 
416 	is_read_unlock(space);
417 
418 	return KERN_SUCCESS;
419 }
420 #endif /* MACH_IPC_DEBUG */
421 
422 /*
423  *	Routine:	mach_port_dnrequest_info
424  *	Purpose:
425  *		Returns information about the dead-name requests
426  *		registered with the named receive right.
427  *	Conditions:
428  *		Nothing locked.
429  *	Returns:
430  *		KERN_SUCCESS		Retrieved information.
431  *		KERN_INVALID_TASK	The space is null.
432  *		KERN_INVALID_TASK	The space is dead.
433  *		KERN_INVALID_NAME	The name doesn't denote a right.
434  *		KERN_INVALID_RIGHT	Name doesn't denote receive rights.
435  */
436 
437 #if !MACH_IPC_DEBUG
438 kern_return_t
mach_port_dnrequest_info(__unused ipc_space_t space,__unused mach_port_name_t name,__unused unsigned int * totalp,__unused unsigned int * usedp)439 mach_port_dnrequest_info(
440 	__unused ipc_space_t            space,
441 	__unused mach_port_name_t       name,
442 	__unused unsigned int   *totalp,
443 	__unused unsigned int   *usedp)
444 {
445 	return KERN_FAILURE;
446 }
447 #else
448 kern_return_t
mach_port_dnrequest_info(ipc_space_t space,mach_port_name_t name,unsigned int * totalp,unsigned int * usedp)449 mach_port_dnrequest_info(
450 	ipc_space_t                     space,
451 	mach_port_name_t                name,
452 	unsigned int                    *totalp,
453 	unsigned int                    *usedp)
454 {
455 	unsigned int total, used;
456 	ipc_port_t port;
457 	kern_return_t kr;
458 
459 	if (space == IS_NULL) {
460 		return KERN_INVALID_TASK;
461 	}
462 
463 	kr = ipc_port_translate_receive(space, name, &port);
464 	if (kr != KERN_SUCCESS) {
465 		return kr;
466 	}
467 	/* port is locked and active */
468 
469 	if (port->ip_requests == IPR_NULL) {
470 		total = 0;
471 		used = 0;
472 	} else {
473 		ipc_port_request_t requests = port->ip_requests;
474 		ipc_port_request_index_t index;
475 
476 		total = requests->ipr_size->its_size;
477 
478 		for (index = 1, used = 0;
479 		    index < total; index++) {
480 			ipc_port_request_t ipr = &requests[index];
481 
482 			if (ipr->ipr_name != MACH_PORT_NULL) {
483 				used++;
484 			}
485 		}
486 	}
487 	ip_mq_unlock(port);
488 
489 	*totalp = total;
490 	*usedp = used;
491 	return KERN_SUCCESS;
492 }
493 #endif /* MACH_IPC_DEBUG */
494 
495 /*
496  *	Routine:	mach_port_kobject [kernel call]
497  *	Purpose:
498  *		Retrieve the type and address of the kernel object
499  *		represented by a send or receive right. Returns
500  *		the kernel address in a mach_vm_address_t to
501  *		mask potential differences in kernel address space
502  *		size.
503  *	Conditions:
504  *		Nothing locked.
505  *	Returns:
506  *		KERN_SUCCESS		Retrieved kernel object info.
507  *		KERN_INVALID_TASK	The space is null.
508  *		KERN_INVALID_TASK	The space is dead.
509  *		KERN_INVALID_NAME	The name doesn't denote a right.
510  *		KERN_INVALID_RIGHT	Name doesn't denote
511  *					send or receive rights.
512  */
513 
514 #if !MACH_IPC_DEBUG
515 kern_return_t
mach_port_kobject_from_user(__unused mach_port_t port,__unused mach_port_name_t name,__unused natural_t * typep,__unused mach_vm_address_t * addrp)516 mach_port_kobject_from_user(
517 	__unused mach_port_t            port,
518 	__unused mach_port_name_t       name,
519 	__unused natural_t              *typep,
520 	__unused mach_vm_address_t      *addrp)
521 {
522 	return KERN_FAILURE;
523 }
524 
525 kern_return_t
mach_port_kobject_description_from_user(__unused mach_port_t port,__unused mach_port_name_t name,__unused natural_t * typep,__unused mach_vm_address_t * addrp,__unused kobject_description_t des)526 mach_port_kobject_description_from_user(
527 	__unused mach_port_t            port,
528 	__unused mach_port_name_t       name,
529 	__unused natural_t              *typep,
530 	__unused mach_vm_address_t      *addrp,
531 	__unused kobject_description_t  des)
532 {
533 	return KERN_FAILURE;
534 }
535 #else
536 kern_return_t
537 mach_port_kobject_description(
538 	ipc_space_t                     space,
539 	mach_port_name_t                name,
540 	natural_t                       *typep,
541 	mach_vm_address_t               *addrp,
542 	kobject_description_t           desc);
543 
544 kern_return_t
mach_port_kobject_description(ipc_space_t space,mach_port_name_t name,natural_t * typep,mach_vm_address_t * addrp,kobject_description_t desc)545 mach_port_kobject_description(
546 	ipc_space_t                     space,
547 	mach_port_name_t                name,
548 	natural_t                       *typep,
549 	mach_vm_address_t               *addrp,
550 	kobject_description_t           desc)
551 {
552 	ipc_entry_bits_t bits;
553 	ipc_object_t object;
554 	kern_return_t kr;
555 	mach_vm_address_t kaddr = 0;
556 	io_object_t obj = NULL;
557 
558 	if (space == IS_NULL) {
559 		return KERN_INVALID_TASK;
560 	}
561 
562 	kr = ipc_right_lookup_read(space, name, &bits, &object);
563 	if (kr != KERN_SUCCESS) {
564 		return kr;
565 	}
566 	/* object is locked and active */
567 
568 	if ((bits & MACH_PORT_TYPE_SEND_RECEIVE) == 0) {
569 		io_unlock(object);
570 		return KERN_INVALID_RIGHT;
571 	}
572 
573 	*typep = (unsigned int)io_kotype(object);
574 	if (io_is_kobject(object)) {
575 		ipc_port_t port = ip_object_to_port(object);
576 		kaddr = (mach_vm_address_t)ipc_kobject_get_raw(port, io_kotype(object));
577 	}
578 	*addrp = 0;
579 
580 	if (desc) {
581 		*desc = '\0';
582 		switch (io_kotype(object)) {
583 		case IKOT_IOKIT_OBJECT:
584 		case IKOT_IOKIT_CONNECT:
585 		case IKOT_IOKIT_IDENT:
586 		case IKOT_UEXT_OBJECT:
587 			obj = (io_object_t) kaddr;
588 			iokit_add_reference(obj, IKOT_IOKIT_OBJECT);
589 			break;
590 
591 		default:
592 			break;
593 		}
594 	}
595 #if (DEVELOPMENT || DEBUG)
596 	*addrp = VM_KERNEL_UNSLIDE_OR_PERM(kaddr);
597 #endif
598 
599 	io_unlock(object);
600 
601 	if (obj) {
602 		iokit_port_object_description(obj, desc);
603 		iokit_remove_reference(obj);
604 	}
605 
606 	return KERN_SUCCESS;
607 }
608 
609 kern_return_t
610 mach_port_kobject(
611 	ipc_space_t                     space,
612 	mach_port_name_t                name,
613 	natural_t                       *typep,
614 	mach_vm_address_t               *addrp);
615 
616 kern_return_t
mach_port_kobject(ipc_space_t space,mach_port_name_t name,natural_t * typep,mach_vm_address_t * addrp)617 mach_port_kobject(
618 	ipc_space_t                     space,
619 	mach_port_name_t                name,
620 	natural_t                       *typep,
621 	mach_vm_address_t               *addrp)
622 {
623 	return mach_port_kobject_description(space, name, typep, addrp, NULL);
624 }
625 
626 kern_return_t
mach_port_kobject_description_from_user(mach_port_t port,mach_port_name_t name,natural_t * typep,mach_vm_address_t * addrp,kobject_description_t desc)627 mach_port_kobject_description_from_user(
628 	mach_port_t                     port,
629 	mach_port_name_t                name,
630 	natural_t                       *typep,
631 	mach_vm_address_t               *addrp,
632 	kobject_description_t           desc)
633 {
634 	kern_return_t kr;
635 
636 	ipc_space_t space = convert_port_to_space_read_no_eval(port);
637 
638 	if (space == IPC_SPACE_NULL) {
639 		return KERN_INVALID_ARGUMENT;
640 	}
641 
642 	kr = mach_port_kobject_description(space, name, typep, addrp, desc);
643 
644 	ipc_space_release(space);
645 	return kr;
646 }
647 
648 kern_return_t
mach_port_kobject_from_user(mach_port_t port,mach_port_name_t name,natural_t * typep,mach_vm_address_t * addrp)649 mach_port_kobject_from_user(
650 	mach_port_t                     port,
651 	mach_port_name_t                name,
652 	natural_t                       *typep,
653 	mach_vm_address_t               *addrp)
654 {
655 	return mach_port_kobject_description_from_user(port, name, typep, addrp, NULL);
656 }
657 
658 #endif /* MACH_IPC_DEBUG */
659 
660 /*
661  *	Routine:	mach_port_kernel_object [Legacy kernel call]
662  *	Purpose:
663  *		Retrieve the type and address of the kernel object
664  *		represented by a send or receive right. Hard-coded
665  *		to return only the low-order 32-bits of the kernel
666  *		object.
667  *	Conditions:
668  *		Nothing locked.
669  *	Returns:
670  *		KERN_SUCCESS		Retrieved kernel object info.
671  *		KERN_INVALID_TASK	The space is null.
672  *		KERN_INVALID_TASK	The space is dead.
673  *		KERN_INVALID_NAME	The name doesn't denote a right.
674  *		KERN_INVALID_RIGHT	Name doesn't denote
675  *					send or receive rights.
676  */
677 
678 #if !MACH_IPC_DEBUG
679 kern_return_t
mach_port_kernel_object_from_user(__unused mach_port_t port,__unused mach_port_name_t name,__unused unsigned int * typep,__unused unsigned int * addrp)680 mach_port_kernel_object_from_user(
681 	__unused mach_port_t            port,
682 	__unused mach_port_name_t       name,
683 	__unused unsigned int           *typep,
684 	__unused unsigned int           *addrp)
685 {
686 	return KERN_FAILURE;
687 }
688 #else
689 kern_return_t
690 mach_port_kernel_object(
691 	ipc_space_t                     space,
692 	mach_port_name_t                name,
693 	unsigned int                    *typep,
694 	unsigned int                    *addrp);
695 
696 kern_return_t
mach_port_kernel_object(ipc_space_t space,mach_port_name_t name,unsigned int * typep,unsigned int * addrp)697 mach_port_kernel_object(
698 	ipc_space_t                     space,
699 	mach_port_name_t                name,
700 	unsigned int                    *typep,
701 	unsigned int                    *addrp)
702 {
703 	mach_vm_address_t addr = 0;
704 	kern_return_t kr;
705 
706 	kr = mach_port_kobject(space, name, typep, &addr);
707 	*addrp = (unsigned int) addr;
708 	return kr;
709 }
710 
711 kern_return_t
mach_port_kernel_object_from_user(mach_port_t port,mach_port_name_t name,unsigned int * typep,unsigned int * addrp)712 mach_port_kernel_object_from_user(
713 	mach_port_t                     port,
714 	mach_port_name_t                name,
715 	unsigned int                    *typep,
716 	unsigned int                    *addrp)
717 {
718 	kern_return_t kr;
719 
720 	ipc_space_t space = convert_port_to_space_read_no_eval(port);
721 
722 	if (space == IPC_SPACE_NULL) {
723 		return KERN_INVALID_ARGUMENT;
724 	}
725 
726 	kr = mach_port_kernel_object(space, name, typep, addrp);
727 
728 	ipc_space_release(space);
729 	return kr;
730 }
731 #endif /* MACH_IPC_DEBUG */
732 
733 #if (DEVELOPMENT || DEBUG)
734 kern_return_t
mach_port_special_reply_port_reset_link(ipc_space_t space,mach_port_name_t name,boolean_t * srp_lost_link)735 mach_port_special_reply_port_reset_link(
736 	ipc_space_t             space,
737 	mach_port_name_t        name,
738 	boolean_t               *srp_lost_link)
739 {
740 	ipc_port_t port;
741 	kern_return_t kr;
742 	thread_t thread = current_thread();
743 
744 	if (space != current_space()) {
745 		return KERN_INVALID_TASK;
746 	}
747 
748 	if (!MACH_PORT_VALID(name)) {
749 		return KERN_INVALID_NAME;
750 	}
751 
752 	if (!IP_VALID(thread->ith_special_reply_port)) {
753 		return KERN_INVALID_VALUE;
754 	}
755 
756 	kr = ipc_port_translate_receive(space, name, &port);
757 	if (kr != KERN_SUCCESS) {
758 		return kr;
759 	}
760 
761 	if (thread->ith_special_reply_port != port) {
762 		ip_mq_unlock(port);
763 		return KERN_INVALID_ARGUMENT;
764 	}
765 
766 	*srp_lost_link = (port->ip_srp_lost_link == 1)? TRUE : FALSE;
767 	port->ip_srp_lost_link = 0;
768 
769 	ip_mq_unlock(port);
770 	return KERN_SUCCESS;
771 }
772 #else
773 kern_return_t
mach_port_special_reply_port_reset_link(__unused ipc_space_t space,__unused mach_port_name_t name,__unused boolean_t * srp_lost_link)774 mach_port_special_reply_port_reset_link(
775 	__unused ipc_space_t            space,
776 	__unused mach_port_name_t       name,
777 	__unused boolean_t              *srp_lost_link)
778 {
779 	return KERN_NOT_SUPPORTED;
780 }
781 #endif
782