xref: /xnu-12377.61.12/osfmk/ipc/mach_debug.c (revision 4d495c6e23c53686cf65f45067f79024cf5dcee8)
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/vm_param.h>
66 #include <mach/kern_return.h>
67 #include <mach/machine/vm_types.h>
68 #include <mach/mach_host_server.h>
69 #include <mach/mach_port_server.h>
70 #include <mach_debug/ipc_info.h>
71 #include <mach_debug/hash_info.h>
72 #include <kern/task_ident.h>
73 
74 #include <kern/host.h>
75 #include <kern/misc_protos.h>
76 #include <vm/vm_map_xnu.h>
77 #include <vm/vm_memory_entry_xnu.h>
78 #include <vm/vm_kern_xnu.h>
79 #include <ipc/port.h>
80 #include <ipc/ipc_types.h>
81 #include <ipc/ipc_space.h>
82 #include <ipc/ipc_port.h>
83 #include <ipc/ipc_hash.h>
84 #include <ipc/ipc_right.h>
85 
86 #include <security/mac_mach_internal.h>
87 #include <device/device_types.h>
88 
89 /*
90  *	Routine:	mach_port_get_srights [kernel call]
91  *	Purpose:
92  *		Retrieve the number of extant send rights
93  *		that a receive right has.
94  *	Conditions:
95  *		Nothing locked.
96  *	Returns:
97  *		KERN_SUCCESS		Retrieved number of send rights.
98  *		KERN_INVALID_TASK	The space is null.
99  *		KERN_INVALID_TASK	The space is dead.
100  *		KERN_INVALID_NAME	The name doesn't denote a right.
101  *		KERN_INVALID_RIGHT	Name doesn't denote receive rights.
102  */
103 
104 kern_return_t
mach_port_get_srights(ipc_space_t space,mach_port_name_t name,mach_port_rights_t * srightsp)105 mach_port_get_srights(
106 	ipc_space_t             space,
107 	mach_port_name_t        name,
108 	mach_port_rights_t      *srightsp)
109 {
110 	ipc_port_t port;
111 	kern_return_t kr;
112 	mach_port_rights_t srights;
113 
114 	if (space == IS_NULL) {
115 		return KERN_INVALID_TASK;
116 	}
117 
118 	kr = ipc_port_translate_receive(space, name, &port);
119 	if (kr != KERN_SUCCESS) {
120 		return kr;
121 	}
122 	/* port is locked and active */
123 
124 	srights = port->ip_srights;
125 	ip_mq_unlock(port);
126 
127 	*srightsp = srights;
128 	return KERN_SUCCESS;
129 }
130 
131 
132 /*
133  *	Routine:	mach_port_space_info
134  *	Purpose:
135  *		Returns information about an IPC space.
136  *	Conditions:
137  *		Nothing locked.  Obeys CountInOut protocol.
138  *	Returns:
139  *		KERN_SUCCESS		Returned information.
140  *		KERN_INVALID_TASK	The space is null.
141  *		KERN_INVALID_TASK	The space is dead.
142  *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
143  */
144 
145 static 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)146 mach_port_space_info(
147 	ipc_space_t                     space,
148 	ipc_info_space_t                *infop,
149 	ipc_info_name_array_t           *tablep,
150 	mach_msg_type_number_t          *tableCntp,
151 	__unused ipc_info_tree_name_array_t     *treep,
152 	__unused mach_msg_type_number_t         *treeCntp)
153 {
154 	const uint32_t BATCH_SIZE = 4 << 10;
155 	ipc_info_name_t *table_info;
156 	vm_offset_t table_addr = 0;
157 	vm_size_t table_size, table_size_needed;
158 	ipc_entry_table_t table;
159 	ipc_entry_num_t tsize;
160 	kern_return_t kr;
161 	vm_map_copy_t copy;
162 
163 	if (space == IS_NULL) {
164 		return KERN_INVALID_TASK;
165 	}
166 
167 	/* start with in-line memory */
168 	table_size = 0;
169 
170 	ipc_object_t *port_pointers = NULL;
171 	ipc_entry_num_t pptrsize = 0;
172 
173 	is_read_lock(space);
174 
175 allocate_loop:
176 	for (;;) {
177 		if (!is_active(space)) {
178 			is_read_unlock(space);
179 			if (table_size != 0) {
180 				kmem_free(ipc_kernel_map,
181 				    table_addr, table_size);
182 				kfree_type(ipc_object_t, pptrsize, port_pointers);
183 				port_pointers = NULL;
184 			}
185 			return KERN_INVALID_TASK;
186 		}
187 
188 		table = is_active_table(space);
189 		tsize = ipc_entry_table_count(table);
190 
191 		table_size_needed =
192 		    vm_map_round_page(tsize * sizeof(ipc_info_name_t),
193 		    VM_MAP_PAGE_MASK(ipc_kernel_map));
194 
195 		if ((table_size_needed <= table_size) &&
196 		    (pptrsize == tsize)) {
197 			break;
198 		}
199 
200 		is_read_unlock(space);
201 
202 		if (table_size != 0) {
203 			kmem_free(ipc_kernel_map, table_addr, table_size);
204 			kfree_type(ipc_object_t, pptrsize, port_pointers);
205 		}
206 		kr = kmem_alloc(ipc_kernel_map, &table_addr, table_size_needed,
207 		    KMA_DATA, VM_KERN_MEMORY_IPC);
208 		if (kr != KERN_SUCCESS) {
209 			return KERN_RESOURCE_SHORTAGE;
210 		}
211 
212 		port_pointers = kalloc_type(ipc_object_t, tsize, Z_WAITOK | Z_ZERO);
213 		if (port_pointers == NULL) {
214 			kmem_free(ipc_kernel_map, table_addr, table_size);
215 			return KERN_RESOURCE_SHORTAGE;
216 		}
217 
218 		table_size = table_size_needed;
219 		pptrsize = tsize;
220 
221 		is_read_lock(space);
222 	}
223 	/* space is read-locked and active; we have enough wired memory */
224 
225 	/* walk the table for this space */
226 	table_info = (ipc_info_name_array_t)table_addr;
227 	for (mach_port_index_t index = 0; index < tsize; index++) {
228 		ipc_info_name_t *iin = &table_info[index];
229 		ipc_entry_t entry = ipc_entry_table_get_nocheck(table, index);
230 		ipc_entry_bits_t bits;
231 
232 		if (index == 0) {
233 			bits = IE_BITS_GEN_MASK;
234 		} else {
235 			bits = entry->ie_bits;
236 		}
237 		iin->iin_name = MACH_PORT_MAKE(index, IE_BITS_GEN(bits));
238 		iin->iin_collision = 0;
239 		iin->iin_type = IE_BITS_TYPE(bits);
240 		if ((bits & MACH_PORT_TYPE_PORT_RIGHTS) != MACH_PORT_TYPE_NONE &&
241 		    entry->ie_request != IE_REQ_NONE) {
242 			ipc_port_t port = entry->ie_port;
243 
244 			assert(IP_VALID(port));
245 			ip_mq_lock(port);
246 			iin->iin_type |= ipc_port_request_type(port, iin->iin_name, entry->ie_request);
247 			ip_mq_unlock(port);
248 		}
249 
250 		iin->iin_urefs = IE_BITS_UREFS(bits);
251 		port_pointers[index] = entry->ie_object;
252 		iin->iin_next = entry->ie_next;
253 		iin->iin_hash = entry->ie_index;
254 
255 		if (index + 1 < tsize && (index + 1) % BATCH_SIZE == 0) {
256 			/*
257 			 * Give the system some breathing room,
258 			 * and check if anything changed,
259 			 * if yes start over.
260 			 */
261 			is_read_unlock(space);
262 			is_read_lock(space);
263 			if (!is_active(space)) {
264 				goto allocate_loop;
265 			}
266 			table = is_active_table(space);
267 			if (tsize < ipc_entry_table_count(table)) {
268 				goto allocate_loop;
269 			}
270 			tsize = ipc_entry_table_count(table);
271 		}
272 	}
273 
274 	/* get the overall space info */
275 	infop->iis_genno_mask = MACH_PORT_NGEN(MACH_PORT_DEAD);
276 	infop->iis_table_size = tsize;
277 
278 	is_read_unlock(space);
279 
280 	/* prepare the table out-of-line data for return */
281 	if (table_size > 0) {
282 		vm_map_size_t used = tsize * sizeof(ipc_info_name_t);
283 		vm_map_size_t keep = vm_map_round_page(used,
284 		    VM_MAP_PAGE_MASK(ipc_kernel_map));
285 
286 		assert(pptrsize >= tsize);
287 		for (int index = 0; index < tsize; index++) {
288 			ipc_info_name_t *iin = &table_info[index];
289 			iin->iin_object = (natural_t)VM_KERNEL_ADDRHASH((uintptr_t)port_pointers[index]);
290 			port_pointers[index] = MACH_PORT_NULL;
291 		}
292 		kfree_type(ipc_object_t, pptrsize, port_pointers);
293 
294 		if (keep < table_size) {
295 			kmem_free(ipc_kernel_map, table_addr + keep,
296 			    table_size - keep);
297 			table_size = keep;
298 		}
299 		if (table_size > used) {
300 			bzero(&table_info[infop->iis_table_size],
301 			    table_size - used);
302 		}
303 
304 		kr = vm_map_unwire(ipc_kernel_map, table_addr,
305 		    table_addr + table_size, FALSE);
306 		assert(kr == KERN_SUCCESS);
307 		kr = vm_map_copyin(ipc_kernel_map, table_addr, used, TRUE, &copy);
308 		assert(kr == KERN_SUCCESS);
309 		*tablep = (ipc_info_name_t *)copy;
310 		*tableCntp = infop->iis_table_size;
311 	} else {
312 		*tablep = (ipc_info_name_t *)0;
313 		*tableCntp = 0;
314 	}
315 
316 	/* splay tree is obsolete, no work to do... */
317 	*treep = (ipc_info_tree_name_t *)0;
318 	*treeCntp = 0;
319 	return KERN_SUCCESS;
320 }
321 
322 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)323 mach_port_space_info_from_user(
324 	mach_port_t                     port,
325 	ipc_info_space_t                *infop,
326 	ipc_info_name_array_t           *tablep,
327 	mach_msg_type_number_t          *tableCntp,
328 	__unused ipc_info_tree_name_array_t     *treep,
329 	__unused mach_msg_type_number_t         *treeCntp)
330 {
331 	kern_return_t kr;
332 
333 	ipc_space_t space = convert_port_to_space_read_no_eval(port);
334 
335 	if (space == IPC_SPACE_NULL) {
336 		return KERN_INVALID_ARGUMENT;
337 	}
338 
339 	kr = mach_port_space_info(space, infop, tablep, tableCntp, treep, treeCntp);
340 
341 	ipc_space_release(space);
342 	return kr;
343 }
344 
345 /*
346  *	Routine:	mach_port_space_basic_info
347  *	Purpose:
348  *		Returns basic information about an IPC space.
349  *	Conditions:
350  *		Nothing locked.
351  *	Returns:
352  *		KERN_SUCCESS		Returned information.
353  *		KERN_FAILURE		The call is not supported.
354  *		KERN_INVALID_TASK	The space is dead.
355  */
356 
357 kern_return_t
mach_port_space_basic_info(ipc_space_t space,ipc_info_space_basic_t * infop)358 mach_port_space_basic_info(
359 	ipc_space_t                     space,
360 	ipc_info_space_basic_t          *infop)
361 {
362 	ipc_entry_num_t tsize;
363 
364 	if (space == IS_NULL) {
365 		return KERN_INVALID_TASK;
366 	}
367 
368 	is_read_lock(space);
369 	if (!is_active(space)) {
370 		is_read_unlock(space);
371 		return KERN_INVALID_TASK;
372 	}
373 
374 	tsize = ipc_entry_table_count(is_active_table(space));
375 
376 	/* get the basic space info */
377 	infop->iisb_genno_mask = MACH_PORT_NGEN(MACH_PORT_DEAD);
378 	infop->iisb_table_size = tsize;
379 	infop->iisb_table_inuse = tsize - space->is_table_free - 1;
380 	infop->iisb_reserved[0] = 0;
381 	infop->iisb_reserved[1] = 0;
382 
383 	is_read_unlock(space);
384 
385 	return KERN_SUCCESS;
386 }
387 
388 /*
389  *	Routine:	mach_port_dnrequest_info
390  *	Purpose:
391  *		Returns information about the dead-name requests
392  *		registered with the named receive right.
393  *	Conditions:
394  *		Nothing locked.
395  *	Returns:
396  *		KERN_SUCCESS		Retrieved information.
397  *		KERN_INVALID_TASK	The space is null.
398  *		KERN_INVALID_TASK	The space is dead.
399  *		KERN_INVALID_NAME	The name doesn't denote a right.
400  *		KERN_INVALID_RIGHT	Name doesn't denote receive rights.
401  */
402 
403 kern_return_t
mach_port_dnrequest_info(ipc_space_t space,mach_port_name_t name,unsigned int * totalp,unsigned int * usedp)404 mach_port_dnrequest_info(
405 	ipc_space_t                     space,
406 	mach_port_name_t                name,
407 	unsigned int                    *totalp,
408 	unsigned int                    *usedp)
409 {
410 	ipc_port_request_table_t requests;
411 	unsigned int total = 0, used = 0;
412 	ipc_port_t port;
413 	kern_return_t kr;
414 
415 	if (space == IS_NULL) {
416 		return KERN_INVALID_TASK;
417 	}
418 
419 	kr = ipc_port_translate_receive(space, name, &port);
420 	if (kr != KERN_SUCCESS) {
421 		return kr;
422 	}
423 	/* port is locked and active */
424 
425 	requests = port->ip_requests;
426 	if (requests) {
427 		ipc_port_request_t ipr = ipc_port_request_table_base(requests);
428 
429 		while ((ipr = ipc_port_request_table_next_elem(requests, ipr))) {
430 			if (ipr->ipr_soright != IP_NULL &&
431 			    ipr->ipr_name != IPR_HOST_NOTIFY) {
432 				used++;
433 			}
434 		}
435 
436 		total = ipc_port_request_table_count(requests);
437 	}
438 	ip_mq_unlock(port);
439 
440 	*totalp = total;
441 	*usedp = used;
442 	return KERN_SUCCESS;
443 }
444 
445 static ipc_info_object_type_t
mach_port_kobject_type(ipc_port_t port)446 mach_port_kobject_type(ipc_port_t port)
447 {
448 #define MAKE_CASE(name) \
449 	case IKOT_ ## name: return IPC_OTYPE_ ## name
450 
451 	switch (ip_type(port)) {
452 		/* thread ports */
453 		MAKE_CASE(THREAD_CONTROL);
454 		MAKE_CASE(THREAD_READ);
455 		MAKE_CASE(THREAD_INSPECT);
456 
457 		/* task ports */
458 		MAKE_CASE(TASK_CONTROL);
459 		MAKE_CASE(TASK_READ);
460 		MAKE_CASE(TASK_INSPECT);
461 		MAKE_CASE(TASK_NAME);
462 
463 		MAKE_CASE(TASK_RESUME);
464 		MAKE_CASE(TASK_ID_TOKEN);
465 		MAKE_CASE(TASK_FATAL);
466 
467 		/* host services, upcalls, security */
468 		MAKE_CASE(HOST);
469 		MAKE_CASE(HOST_PRIV);
470 		MAKE_CASE(CLOCK);
471 		MAKE_CASE(PROCESSOR);
472 		MAKE_CASE(PROCESSOR_SET);
473 		MAKE_CASE(PROCESSOR_SET_NAME);
474 
475 		/* common userspace used ports */
476 		MAKE_CASE(EVENTLINK);
477 		MAKE_CASE(FILEPORT);
478 		MAKE_CASE(SEMAPHORE);
479 		MAKE_CASE(VOUCHER);
480 		MAKE_CASE(WORK_INTERVAL);
481 
482 		/* VM ports */
483 		MAKE_CASE(MEMORY_OBJECT);
484 		MAKE_CASE(NAMED_ENTRY);
485 
486 		/* IOKit & exclaves ports */
487 		MAKE_CASE(MAIN_DEVICE);
488 		MAKE_CASE(IOKIT_IDENT);
489 		MAKE_CASE(IOKIT_CONNECT);
490 		MAKE_CASE(IOKIT_OBJECT);
491 		MAKE_CASE(UEXT_OBJECT);
492 		MAKE_CASE(EXCLAVES_RESOURCE);
493 
494 		/* misc. */
495 		MAKE_CASE(ARCADE_REG);
496 		MAKE_CASE(AU_SESSIONPORT);
497 		MAKE_CASE(HYPERVISOR);
498 		MAKE_CASE(KCDATA);
499 		MAKE_CASE(UND_REPLY);
500 		MAKE_CASE(UX_HANDLER);
501 
502 	case IOT_TIMER_PORT:
503 		return IPC_OTYPE_TIMER;
504 
505 	default:
506 		return IPC_OTYPE_UNKNOWN;
507 	}
508 #undef MAKE_CASE
509 }
510 
511 /*
512  *	Routine:	mach_port_kobject [kernel call]
513  *	Purpose:
514  *		Retrieve the type and address of the kernel object
515  *		represented by a send or receive right. Returns
516  *		the kernel address in a mach_vm_address_t to
517  *		mask potential differences in kernel address space
518  *		size.
519  *	Conditions:
520  *		Nothing locked.
521  *	Returns:
522  *		KERN_SUCCESS		Retrieved kernel object info.
523  *		KERN_INVALID_TASK	The space is null.
524  *		KERN_INVALID_TASK	The space is dead.
525  *		KERN_INVALID_NAME	The name doesn't denote a right.
526  *		KERN_INVALID_RIGHT	Name doesn't denote
527  *					send or receive rights.
528  */
529 
530 static kern_return_t
mach_port_kobject_description(ipc_space_t space,mach_port_name_t name,ipc_info_object_type_t * typep,mach_vm_address_t * addrp,kobject_description_t desc)531 mach_port_kobject_description(
532 	ipc_space_t                     space,
533 	mach_port_name_t                name,
534 	ipc_info_object_type_t          *typep,
535 	mach_vm_address_t               *addrp,
536 	kobject_description_t           desc)
537 {
538 	ipc_entry_bits_t bits;
539 	ipc_object_t ipc_object;
540 	kern_return_t kr;
541 	mach_vm_address_t kaddr = 0;
542 
543 	if (space == IS_NULL) {
544 		return KERN_INVALID_TASK;
545 	}
546 
547 	kr = ipc_right_lookup_read(space, name, &bits, &ipc_object);
548 	if (kr != KERN_SUCCESS) {
549 		return kr;
550 	}
551 	/* object is locked and active */
552 
553 	if ((bits & MACH_PORT_TYPE_SEND_RECEIVE) == 0) {
554 		io_unlock(ipc_object);
555 		return KERN_INVALID_RIGHT;
556 	}
557 
558 	ipc_port_t port = ip_object_to_port(ipc_object);
559 	*typep = mach_port_kobject_type(port);
560 	if (ip_is_kobject(port)) {
561 		kaddr = (mach_vm_address_t)ipc_kobject_get_raw(port, ip_type(port));
562 	}
563 	*addrp = 0;
564 
565 	if (desc) {
566 		*desc = '\0';
567 		switch (ip_type(port)) {
568 		case IKOT_IOKIT_OBJECT:
569 		case IKOT_IOKIT_CONNECT:
570 		case IKOT_IOKIT_IDENT:
571 		case IKOT_UEXT_OBJECT:
572 		{
573 			io_kobject_t io_kobject = (io_kobject_t)kaddr;
574 			if (io_kobject) {
575 				iokit_kobject_retain(io_kobject);
576 				io_unlock(ipc_object);
577 
578 				// IKOT_IOKIT_OBJECT since iokit_remove_reference() follows
579 				io_object_t io_object = iokit_copy_object_for_consumed_kobject(io_kobject);
580 				io_kobject = NULL;
581 				if (io_object) {
582 					iokit_port_object_description(io_object, desc);
583 					iokit_remove_reference(io_object);
584 					io_object = NULL;
585 				}
586 				goto unlocked;
587 			}
588 			break;
589 		}
590 		case IKOT_TASK_ID_TOKEN:
591 		{
592 			task_id_token_t token;
593 			token = (task_id_token_t)ipc_kobject_get_stable(port, IKOT_TASK_ID_TOKEN);
594 			snprintf(desc, KOBJECT_DESCRIPTION_LENGTH, "%d,%llu,%d", token->ident.p_pid, token->ident.p_uniqueid, token->ident.p_idversion);
595 			break;
596 		}
597 		case IKOT_NAMED_ENTRY:
598 		{
599 			vm_named_entry_t named_entry = (vm_named_entry_t)ipc_kobject_get_stable(port, IKOT_NAMED_ENTRY);
600 			mach_memory_entry_describe(named_entry, desc);
601 			break;
602 		}
603 		default:
604 			break;
605 		}
606 	}
607 
608 	io_unlock(ipc_object);
609 
610 unlocked:
611 #if (DEVELOPMENT || DEBUG)
612 	*addrp = VM_KERNEL_ADDRHASH(kaddr);
613 #endif
614 	return KERN_SUCCESS;
615 }
616 
617 kern_return_t
mach_port_kobject_description_from_user(mach_port_t port,mach_port_name_t name,ipc_info_object_type_t * typep,mach_vm_address_t * addrp,kobject_description_t desc)618 mach_port_kobject_description_from_user(
619 	mach_port_t                     port,
620 	mach_port_name_t                name,
621 	ipc_info_object_type_t          *typep,
622 	mach_vm_address_t               *addrp,
623 	kobject_description_t           desc)
624 {
625 	kern_return_t kr;
626 
627 	ipc_space_t space = convert_port_to_space_read_no_eval(port);
628 
629 	if (space == IPC_SPACE_NULL) {
630 		return KERN_INVALID_ARGUMENT;
631 	}
632 
633 	kr = mach_port_kobject_description(space, name, typep, addrp, desc);
634 
635 	ipc_space_release(space);
636 	return kr;
637 }
638 
639 kern_return_t
mach_port_kobject_from_user(mach_port_t port,mach_port_name_t name,ipc_info_object_type_t * typep,mach_vm_address_t * addrp)640 mach_port_kobject_from_user(
641 	mach_port_t                     port,
642 	mach_port_name_t                name,
643 	ipc_info_object_type_t          *typep,
644 	mach_vm_address_t               *addrp)
645 {
646 	return mach_port_kobject_description_from_user(port, name, typep, addrp, NULL);
647 }
648 
649 #if (DEVELOPMENT || DEBUG)
650 kern_return_t
mach_port_special_reply_port_reset_link(ipc_space_t space,mach_port_name_t name,boolean_t * srp_lost_link)651 mach_port_special_reply_port_reset_link(
652 	ipc_space_t             space,
653 	mach_port_name_t        name,
654 	boolean_t               *srp_lost_link)
655 {
656 	ipc_port_t port;
657 	kern_return_t kr;
658 	thread_t thread = current_thread();
659 
660 	if (space != current_space()) {
661 		return KERN_INVALID_TASK;
662 	}
663 
664 	if (!MACH_PORT_VALID(name)) {
665 		return KERN_INVALID_NAME;
666 	}
667 
668 	if (!IP_VALID(thread->ith_special_reply_port)) {
669 		return KERN_INVALID_VALUE;
670 	}
671 
672 	kr = ipc_port_translate_receive(space, name, &port);
673 	if (kr != KERN_SUCCESS) {
674 		return kr;
675 	}
676 
677 	if (thread->ith_special_reply_port != port) {
678 		ip_mq_unlock(port);
679 		return KERN_INVALID_ARGUMENT;
680 	}
681 
682 	*srp_lost_link = (port->ip_srp_lost_link == 1)? TRUE : FALSE;
683 	port->ip_srp_lost_link = 0;
684 
685 	ip_mq_unlock(port);
686 	return KERN_SUCCESS;
687 }
688 #else
689 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)690 mach_port_special_reply_port_reset_link(
691 	__unused ipc_space_t            space,
692 	__unused mach_port_name_t       name,
693 	__unused boolean_t              *srp_lost_link)
694 {
695 	return KERN_NOT_SUPPORTED;
696 }
697 #endif
698