xref: /xnu-8020.140.41/iokit/Kernel/IOUserClient.cpp (revision 27b03b360a988dfd3dfdf34262bb0042026747cc)
1 /*
2  * Copyright (c) 1998-2019 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 
30 #include <libkern/c++/OSKext.h>
31 #include <libkern/c++/OSSharedPtr.h>
32 #include <IOKit/IOKitServer.h>
33 #include <IOKit/IOKitKeysPrivate.h>
34 #include <IOKit/IOUserClient.h>
35 #include <IOKit/IOService.h>
36 #include <IOKit/IORegistryEntry.h>
37 #include <IOKit/IOCatalogue.h>
38 #include <IOKit/IOMemoryDescriptor.h>
39 #include <IOKit/IOBufferMemoryDescriptor.h>
40 #include <IOKit/IOLib.h>
41 #include <IOKit/IOBSD.h>
42 #include <IOKit/IOStatisticsPrivate.h>
43 #include <IOKit/IOTimeStamp.h>
44 #include <IOKit/IODeviceTreeSupport.h>
45 #include <IOKit/IOUserServer.h>
46 #include <IOKit/system.h>
47 #include <libkern/OSDebug.h>
48 #include <DriverKit/OSAction.h>
49 #include <sys/proc.h>
50 #include <sys/kauth.h>
51 #include <sys/codesign.h>
52 
53 #include <mach/sdt.h>
54 #include <os/hash.h>
55 
56 #include <libkern/amfi/amfi.h>
57 
58 #if CONFIG_MACF
59 
60 extern "C" {
61 #include <security/mac_framework.h>
62 };
63 #include <sys/kauth.h>
64 
65 #define IOMACF_LOG 0
66 
67 #endif /* CONFIG_MACF */
68 
69 #include <IOKit/assert.h>
70 
71 #include "IOServicePrivate.h"
72 #include "IOKitKernelInternal.h"
73 
74 #define SCALAR64(x) ((io_user_scalar_t)((unsigned int)x))
75 #define SCALAR32(x) ((uint32_t )x)
76 #define ARG32(x)    ((void *)(uintptr_t)SCALAR32(x))
77 #define REF64(x)    ((io_user_reference_t)((UInt64)(x)))
78 #define REF32(x)    ((int)(x))
79 
80 enum{
81 	kIOUCAsync0Flags          = 3ULL,
82 	kIOUCAsync64Flag          = 1ULL,
83 	kIOUCAsyncErrorLoggedFlag = 2ULL
84 };
85 
86 #if IOKITSTATS
87 
88 #define IOStatisticsRegisterCounter() \
89 do { \
90 	reserved->counter = IOStatistics::registerUserClient(this); \
91 } while (0)
92 
93 #define IOStatisticsUnregisterCounter() \
94 do { \
95 	if (reserved) \
96 	        IOStatistics::unregisterUserClient(reserved->counter); \
97 } while (0)
98 
99 #define IOStatisticsClientCall() \
100 do { \
101 	IOStatistics::countUserClientCall(client); \
102 } while (0)
103 
104 #else
105 
106 #define IOStatisticsRegisterCounter()
107 #define IOStatisticsUnregisterCounter()
108 #define IOStatisticsClientCall()
109 
110 #endif /* IOKITSTATS */
111 
112 #if DEVELOPMENT || DEBUG
113 
114 #define FAKE_STACK_FRAME(a)                                             \
115 	const void ** __frameptr;                                       \
116 	const void  * __retaddr;                                        \
117 	__frameptr = (typeof(__frameptr)) __builtin_frame_address(0);   \
118 	__retaddr = __frameptr[1];                                      \
119 	__frameptr[1] = (a);
120 
121 #define FAKE_STACK_FRAME_END()                                          \
122 	__frameptr[1] = __retaddr;
123 
124 #else /* DEVELOPMENT || DEBUG */
125 
126 #define FAKE_STACK_FRAME(a)
127 #define FAKE_STACK_FRAME_END()
128 
129 #endif /* DEVELOPMENT || DEBUG */
130 
131 #define ASYNC_REF_COUNT         (sizeof(io_async_ref_t) / sizeof(natural_t))
132 #define ASYNC_REF64_COUNT       (sizeof(io_async_ref64_t) / sizeof(io_user_reference_t))
133 
134 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
135 
136 extern "C" {
137 #include <mach/mach_traps.h>
138 #include <vm/vm_map.h>
139 } /* extern "C" */
140 
141 struct IOMachPortHashList;
142 
143 static_assert(IKOT_MAX_TYPE <= 255);
144 
145 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
146 
147 // IOMachPort maps OSObjects to ports, avoiding adding an ivar to OSObject.
148 class IOMachPort : public OSObject
149 {
150 	OSDeclareDefaultStructors(IOMachPort);
151 public:
152 	SLIST_ENTRY(IOMachPort) link;
153 	ipc_port_t  port;
154 	OSObject*   object;
155 	UInt32      mscount;
156 	UInt8       holdDestroy;
157 	UInt8       type;
158 
159 	static IOMachPort* withObjectAndType(OSObject *obj, ipc_kobject_type_t type);
160 
161 	static IOMachPortHashList* bucketForObject(OSObject *obj,
162 	    ipc_kobject_type_t type);
163 
164 	static LIBKERN_RETURNS_NOT_RETAINED IOMachPort* portForObjectInBucket(IOMachPortHashList *bucket, OSObject *obj, ipc_kobject_type_t type);
165 
166 	static bool noMoreSendersForObject( OSObject * obj,
167 	    ipc_kobject_type_t type, mach_port_mscount_t * mscount );
168 	static void releasePortForObject( OSObject * obj,
169 	    ipc_kobject_type_t type );
170 	static void setHoldDestroy( OSObject * obj, ipc_kobject_type_t type );
171 
172 	static mach_port_name_t makeSendRightForTask( task_t task,
173 	    io_object_t obj, ipc_kobject_type_t type );
174 
175 	virtual void free() APPLE_KEXT_OVERRIDE;
176 };
177 
178 #define super OSObject
179 OSDefineMetaClassAndStructorsWithZone(IOMachPort, OSObject, ZC_ZFREE_CLEARMEM)
180 
181 static IOLock *         gIOObjectPortLock;
182 IOLock *                gIOUserServerLock;
183 
184 SECURITY_READ_ONLY_LATE(const struct io_filter_callbacks *) gIOUCFilterCallbacks;
185 
186 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
187 
188 SLIST_HEAD(IOMachPortHashList, IOMachPort);
189 
190 #if defined(XNU_TARGET_OS_OSX)
191 #define PORT_HASH_SIZE 4096
192 #else /* defined(!XNU_TARGET_OS_OSX) */
193 #define PORT_HASH_SIZE 256
194 #endif /* !defined(!XNU_TARGET_OS_OSX) */
195 
196 IOMachPortHashList gIOMachPortHash[PORT_HASH_SIZE];
197 
198 void
IOMachPortInitialize(void)199 IOMachPortInitialize(void)
200 {
201 	for (size_t i = 0; i < PORT_HASH_SIZE; i++) {
202 		SLIST_INIT(&gIOMachPortHash[i]);
203 	}
204 }
205 
206 IOMachPortHashList*
bucketForObject(OSObject * obj,ipc_kobject_type_t type)207 IOMachPort::bucketForObject(OSObject *obj, ipc_kobject_type_t type )
208 {
209 	return &gIOMachPortHash[os_hash_kernel_pointer(obj) % PORT_HASH_SIZE];
210 }
211 
212 IOMachPort*
portForObjectInBucket(IOMachPortHashList * bucket,OSObject * obj,ipc_kobject_type_t type)213 IOMachPort::portForObjectInBucket(IOMachPortHashList *bucket, OSObject *obj, ipc_kobject_type_t type)
214 {
215 	IOMachPort *machPort;
216 
217 	SLIST_FOREACH(machPort, bucket, link) {
218 		if (machPort->object == obj && machPort->type == type) {
219 			return machPort;
220 		}
221 	}
222 	return NULL;
223 }
224 
225 IOMachPort*
withObjectAndType(OSObject * obj,ipc_kobject_type_t type)226 IOMachPort::withObjectAndType(OSObject *obj, ipc_kobject_type_t type)
227 {
228 	IOMachPort *machPort = NULL;
229 
230 	machPort = new IOMachPort;
231 	if (__improbable(machPort && !machPort->init())) {
232 		OSSafeReleaseNULL(machPort);
233 		return NULL;
234 	}
235 
236 	machPort->object = obj;
237 	machPort->type = (typeof(machPort->type))type;
238 	machPort->port = iokit_alloc_object_port(obj, type);
239 
240 	obj->taggedRetain(OSTypeID(OSCollection));
241 	machPort->mscount++;
242 
243 	return machPort;
244 }
245 
246 bool
noMoreSendersForObject(OSObject * obj,ipc_kobject_type_t type,mach_port_mscount_t * mscount)247 IOMachPort::noMoreSendersForObject( OSObject * obj,
248     ipc_kobject_type_t type, mach_port_mscount_t * mscount )
249 {
250 	IOMachPort *machPort = NULL;
251 	IOUserClient *uc;
252 	OSAction *action;
253 	bool destroyed = true;
254 
255 	IOMachPortHashList *bucket = IOMachPort::bucketForObject(obj, type);
256 
257 	obj->retain();
258 
259 	lck_mtx_lock(gIOObjectPortLock);
260 
261 	machPort = IOMachPort::portForObjectInBucket(bucket, obj, type);
262 
263 	if (machPort) {
264 		destroyed = (machPort->mscount <= *mscount);
265 		if (!destroyed) {
266 			*mscount = machPort->mscount;
267 			lck_mtx_unlock(gIOObjectPortLock);
268 		} else {
269 			if ((IKOT_IOKIT_CONNECT == type) && (uc = OSDynamicCast(IOUserClient, obj))) {
270 				uc->noMoreSenders();
271 			}
272 			SLIST_REMOVE(bucket, machPort, IOMachPort, link);
273 
274 			lck_mtx_unlock(gIOObjectPortLock);
275 
276 			OS_ANALYZER_SUPPRESS("77508635") OSSafeReleaseNULL(machPort);
277 
278 			obj->taggedRelease(OSTypeID(OSCollection));
279 		}
280 	} else {
281 		lck_mtx_unlock(gIOObjectPortLock);
282 	}
283 
284 	if ((IKOT_UEXT_OBJECT == type) && (action = OSDynamicCast(OSAction, obj))) {
285 		action->Aborted();
286 	}
287 
288 	obj->release();
289 
290 	return destroyed;
291 }
292 
293 void
releasePortForObject(OSObject * obj,ipc_kobject_type_t type)294 IOMachPort::releasePortForObject( OSObject * obj,
295     ipc_kobject_type_t type )
296 {
297 	IOMachPort *machPort;
298 	IOMachPortHashList *bucket = IOMachPort::bucketForObject(obj, type);
299 
300 	assert(IKOT_IOKIT_CONNECT != type);
301 
302 	lck_mtx_lock(gIOObjectPortLock);
303 
304 	machPort = IOMachPort::portForObjectInBucket(bucket, obj, type);
305 
306 	if (machPort && !machPort->holdDestroy) {
307 		obj->retain();
308 		SLIST_REMOVE(bucket, machPort, IOMachPort, link);
309 
310 		lck_mtx_unlock(gIOObjectPortLock);
311 
312 		OS_ANALYZER_SUPPRESS("77508635") OSSafeReleaseNULL(machPort);
313 
314 		obj->taggedRelease(OSTypeID(OSCollection));
315 		obj->release();
316 	} else {
317 		lck_mtx_unlock(gIOObjectPortLock);
318 	}
319 }
320 
321 void
setHoldDestroy(OSObject * obj,ipc_kobject_type_t type)322 IOMachPort::setHoldDestroy( OSObject * obj, ipc_kobject_type_t type )
323 {
324 	IOMachPort *        machPort;
325 
326 	IOMachPortHashList *bucket = IOMachPort::bucketForObject(obj, type);
327 	lck_mtx_lock(gIOObjectPortLock);
328 
329 	machPort = IOMachPort::portForObjectInBucket(bucket, obj, type);
330 
331 	if (machPort) {
332 		machPort->holdDestroy = true;
333 	}
334 
335 	lck_mtx_unlock(gIOObjectPortLock);
336 }
337 
338 void
IOMachPortDestroyUserReferences(OSObject * obj,natural_t type)339 IOMachPortDestroyUserReferences(OSObject * obj, natural_t type)
340 {
341 	IOMachPort::releasePortForObject(obj, type);
342 }
343 
344 void
destroyUserReferences(OSObject * obj)345 IOUserClient::destroyUserReferences( OSObject * obj )
346 {
347 	IOMachPort *machPort;
348 
349 	IOMachPort::releasePortForObject( obj, IKOT_IOKIT_OBJECT );
350 
351 	// panther, 3160200
352 	// IOMachPort::releasePortForObject( obj, IKOT_IOKIT_CONNECT );
353 
354 	obj->retain();
355 	IOMachPortHashList *bucket = IOMachPort::bucketForObject(obj, IKOT_IOKIT_CONNECT);
356 	IOMachPortHashList *mappingBucket = NULL;
357 
358 	lck_mtx_lock(gIOObjectPortLock);
359 
360 	IOUserClient * uc = OSDynamicCast(IOUserClient, obj);
361 	if (uc && uc->mappings) {
362 		mappingBucket = IOMachPort::bucketForObject(uc->mappings, IKOT_IOKIT_CONNECT);
363 	}
364 
365 	machPort = IOMachPort::portForObjectInBucket(bucket, obj, IKOT_IOKIT_CONNECT);
366 
367 	if (machPort == NULL) {
368 		lck_mtx_unlock(gIOObjectPortLock);
369 		goto end;
370 	}
371 
372 	SLIST_REMOVE(bucket, machPort, IOMachPort, link);
373 	obj->taggedRelease(OSTypeID(OSCollection));
374 
375 	if (uc) {
376 		uc->noMoreSenders();
377 		if (uc->mappings) {
378 			uc->mappings->taggedRetain(OSTypeID(OSCollection));
379 			machPort->object = uc->mappings;
380 			SLIST_INSERT_HEAD(mappingBucket, machPort, link);
381 			iokit_switch_object_port(machPort->port, uc->mappings, IKOT_IOKIT_CONNECT);
382 
383 			lck_mtx_unlock(gIOObjectPortLock);
384 
385 			OSSafeReleaseNULL(uc->mappings);
386 		} else {
387 			lck_mtx_unlock(gIOObjectPortLock);
388 			OS_ANALYZER_SUPPRESS("77508635") OSSafeReleaseNULL(machPort);
389 		}
390 	} else {
391 		lck_mtx_unlock(gIOObjectPortLock);
392 		OS_ANALYZER_SUPPRESS("77508635") OSSafeReleaseNULL(machPort);
393 	}
394 
395 
396 end:
397 	OSSafeReleaseNULL(obj);
398 }
399 
400 mach_port_name_t
makeSendRightForTask(task_t task,io_object_t obj,ipc_kobject_type_t type)401 IOMachPort::makeSendRightForTask( task_t task,
402     io_object_t obj, ipc_kobject_type_t type )
403 {
404 	return iokit_make_send_right( task, obj, type );
405 }
406 
407 void
free(void)408 IOMachPort::free( void )
409 {
410 	if (port) {
411 		iokit_destroy_object_port( port, type );
412 	}
413 	super::free();
414 }
415 
416 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
417 
418 static bool
IOTaskRegistryCompatibility(task_t task)419 IOTaskRegistryCompatibility(task_t task)
420 {
421 	return false;
422 }
423 
424 static void
IOTaskRegistryCompatibilityMatching(task_t task,OSDictionary * matching)425 IOTaskRegistryCompatibilityMatching(task_t task, OSDictionary * matching)
426 {
427 	matching->setObject(gIOServiceNotificationUserKey, kOSBooleanTrue);
428 	if (!IOTaskRegistryCompatibility(task)) {
429 		return;
430 	}
431 	matching->setObject(gIOCompatibilityMatchKey, kOSBooleanTrue);
432 }
433 
434 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
435 
OSDefineMetaClassAndStructors(IOUserIterator,OSIterator)436 OSDefineMetaClassAndStructors( IOUserIterator, OSIterator )
437 
438 IOUserIterator *
439 IOUserIterator::withIterator(OSIterator * iter)
440 {
441 	IOUserIterator * me;
442 
443 	if (!iter) {
444 		return NULL;
445 	}
446 
447 	me = new IOUserIterator;
448 	if (me && !me->init()) {
449 		me->release();
450 		me = NULL;
451 	}
452 	if (!me) {
453 		iter->release();
454 		return me;
455 	}
456 	me->userIteratorObject = iter;
457 
458 	return me;
459 }
460 
461 bool
init(void)462 IOUserIterator::init( void )
463 {
464 	if (!OSObject::init()) {
465 		return false;
466 	}
467 
468 	lock = IOLockAlloc();
469 	if (!lock) {
470 		return false;
471 	}
472 
473 	return true;
474 }
475 
476 void
free()477 IOUserIterator::free()
478 {
479 	if (userIteratorObject) {
480 		userIteratorObject->release();
481 	}
482 	if (lock) {
483 		IOLockFree(lock);
484 	}
485 	OSObject::free();
486 }
487 
488 void
reset()489 IOUserIterator::reset()
490 {
491 	IOLockLock(lock);
492 	assert(OSDynamicCast(OSIterator, userIteratorObject));
493 	((OSIterator *)userIteratorObject)->reset();
494 	IOLockUnlock(lock);
495 }
496 
497 bool
isValid()498 IOUserIterator::isValid()
499 {
500 	bool ret;
501 
502 	IOLockLock(lock);
503 	assert(OSDynamicCast(OSIterator, userIteratorObject));
504 	ret = ((OSIterator *)userIteratorObject)->isValid();
505 	IOLockUnlock(lock);
506 
507 	return ret;
508 }
509 
510 OSObject *
getNextObject()511 IOUserIterator::getNextObject()
512 {
513 	assert(false);
514 	return NULL;
515 }
516 
517 OSObject *
copyNextObject()518 IOUserIterator::copyNextObject()
519 {
520 	OSObject * ret = NULL;
521 
522 	IOLockLock(lock);
523 	if (userIteratorObject) {
524 		ret = ((OSIterator *)userIteratorObject)->getNextObject();
525 		if (ret) {
526 			ret->retain();
527 		}
528 	}
529 	IOLockUnlock(lock);
530 
531 	return ret;
532 }
533 
534 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
535 extern "C" {
536 // functions called from osfmk/device/iokit_rpc.c
537 
538 void
iokit_port_object_description(io_object_t obj,kobject_description_t desc)539 iokit_port_object_description(io_object_t obj, kobject_description_t desc)
540 {
541 	IORegistryEntry    * regEntry;
542 	IOUserNotification * __unused noti;
543 	_IOServiceNotifier * __unused serviceNoti;
544 	OSSerialize        * __unused s;
545 	OSDictionary       * __unused matching = NULL;
546 
547 	if ((regEntry = OSDynamicCast(IORegistryEntry, obj))) {
548 		snprintf(desc, KOBJECT_DESCRIPTION_LENGTH, "%s(0x%qx)", obj->getMetaClass()->getClassName(), regEntry->getRegistryEntryID());
549 #if DEVELOPMENT || DEBUG
550 	} else if ((noti = OSDynamicCast(IOUserNotification, obj))) {
551 		// serviceNoti->matching may become NULL if the port gets a no-senders notification, so we have to lock gIOObjectPortLock
552 		IOLockLock(gIOObjectPortLock);
553 		serviceNoti = OSDynamicCast(_IOServiceNotifier, noti->userIteratorObject);
554 		if (serviceNoti && (matching = serviceNoti->matching)) {
555 			matching->retain();
556 		}
557 		IOLockUnlock(gIOObjectPortLock);
558 
559 		if (matching) {
560 			s = OSSerialize::withCapacity((unsigned int) page_size);
561 			if (s && matching->serialize(s)) {
562 				snprintf(desc, KOBJECT_DESCRIPTION_LENGTH, "%s(%s)", obj->getMetaClass()->getClassName(), s->text());
563 			}
564 			OSSafeReleaseNULL(s);
565 			OSSafeReleaseNULL(matching);
566 		}
567 #endif /* DEVELOPMENT || DEBUG */
568 	} else {
569 		snprintf(desc, KOBJECT_DESCRIPTION_LENGTH, "%s", obj->getMetaClass()->getClassName());
570 	}
571 }
572 
573 // FIXME: Implementation of these functions are hidden from the static analyzer.
574 // As for now, the analyzer doesn't consistently support wrapper functions
575 // for retain and release.
576 #ifndef __clang_analyzer__
577 void
iokit_add_reference(io_object_t obj,natural_t type)578 iokit_add_reference( io_object_t obj, natural_t type )
579 {
580 	IOUserClient * uc;
581 
582 	if (!obj) {
583 		return;
584 	}
585 
586 	if ((IKOT_IOKIT_CONNECT == type)
587 	    && (uc = OSDynamicCast(IOUserClient, obj))) {
588 		OSIncrementAtomic(&uc->__ipc);
589 	}
590 
591 	obj->retain();
592 }
593 
594 void
iokit_remove_reference(io_object_t obj)595 iokit_remove_reference( io_object_t obj )
596 {
597 	if (obj) {
598 		obj->release();
599 	}
600 }
601 #endif // __clang_analyzer__
602 
603 void
iokit_remove_connect_reference(LIBKERN_CONSUMED io_object_t obj)604 iokit_remove_connect_reference(LIBKERN_CONSUMED io_object_t obj )
605 {
606 	IOUserClient * uc;
607 	bool           finalize = false;
608 
609 	if (!obj) {
610 		return;
611 	}
612 
613 	if ((uc = OSDynamicCast(IOUserClient, obj))) {
614 		if (1 == OSDecrementAtomic(&uc->__ipc) && uc->isInactive()) {
615 			IOLockLock(gIOObjectPortLock);
616 			if ((finalize = uc->__ipcFinal)) {
617 				uc->__ipcFinal = false;
618 			}
619 			IOLockUnlock(gIOObjectPortLock);
620 		}
621 		if (finalize) {
622 			uc->scheduleFinalize(true);
623 		}
624 	}
625 
626 	obj->release();
627 }
628 
629 bool
finalizeUserReferences(OSObject * obj)630 IOUserClient::finalizeUserReferences(OSObject * obj)
631 {
632 	IOUserClient * uc;
633 	bool           ok = true;
634 
635 	if ((uc = OSDynamicCast(IOUserClient, obj))) {
636 		IOLockLock(gIOObjectPortLock);
637 		if ((uc->__ipcFinal = (0 != uc->__ipc))) {
638 			ok = false;
639 		}
640 		IOLockUnlock(gIOObjectPortLock);
641 	}
642 	return ok;
643 }
644 
645 ipc_port_t
iokit_port_for_object(io_object_t obj,ipc_kobject_type_t type)646 iokit_port_for_object( io_object_t obj, ipc_kobject_type_t type )
647 {
648 	IOMachPort *machPort = NULL;
649 	ipc_port_t   port = NULL;
650 
651 	IOMachPortHashList *bucket = IOMachPort::bucketForObject(obj, type);
652 
653 	lck_mtx_lock(gIOObjectPortLock);
654 
655 	machPort = IOMachPort::portForObjectInBucket(bucket, obj, type);
656 
657 	if (__improbable(machPort == NULL)) {
658 		machPort = IOMachPort::withObjectAndType(obj, type);
659 		if (__improbable(machPort == NULL)) {
660 			goto end;
661 		}
662 		SLIST_INSERT_HEAD(bucket, machPort, link);
663 	} else {
664 		machPort->mscount++;
665 	}
666 
667 	iokit_retain_port(machPort->port);
668 	port = machPort->port;
669 
670 end:
671 	lck_mtx_unlock(gIOObjectPortLock);
672 
673 	return port;
674 }
675 
676 kern_return_t
iokit_client_died(io_object_t obj,ipc_port_t,ipc_kobject_type_t type,mach_port_mscount_t * mscount)677 iokit_client_died( io_object_t obj, ipc_port_t /* port */,
678     ipc_kobject_type_t type, mach_port_mscount_t * mscount )
679 {
680 	IOUserClient *      client;
681 	IOMemoryMap *       map;
682 	IOUserNotification * notify;
683 	IOUserServerCheckInToken * token;
684 
685 	if (!IOMachPort::noMoreSendersForObject( obj, type, mscount )) {
686 		return kIOReturnNotReady;
687 	}
688 
689 	switch (type) {
690 	case IKOT_IOKIT_CONNECT:
691 		if ((client = OSDynamicCast( IOUserClient, obj ))) {
692 			IOStatisticsClientCall();
693 			IORWLockWrite(client->lock);
694 			client->clientDied();
695 			IORWLockUnlock(client->lock);
696 		}
697 		break;
698 	case IKOT_IOKIT_OBJECT:
699 		if ((map = OSDynamicCast( IOMemoryMap, obj ))) {
700 			map->taskDied();
701 		} else if ((notify = OSDynamicCast( IOUserNotification, obj ))) {
702 			notify->setNotification( NULL );
703 		}
704 		break;
705 	case IKOT_IOKIT_IDENT:
706 		if ((token = OSDynamicCast( IOUserServerCheckInToken, obj ))) {
707 			token->cancel();
708 		}
709 		break;
710 	}
711 
712 	return kIOReturnSuccess;
713 }
714 };      /* extern "C" */
715 
716 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
717 
718 class IOServiceUserNotification : public IOUserNotification
719 {
720 	OSDeclareDefaultStructors(IOServiceUserNotification);
721 
722 	struct PingMsg {
723 		mach_msg_header_t               msgHdr;
724 		OSNotificationHeader64          notifyHeader;
725 	};
726 
727 	enum { kMaxOutstanding = 1024 };
728 
729 	ipc_port_t          remotePort;
730 	void                *msgReference;
731 	mach_msg_size_t     msgReferenceSize;
732 	natural_t           msgType;
733 	OSArray     *       newSet;
734 	bool                armed;
735 	bool                ipcLogged;
736 
737 public:
738 
739 	virtual bool init( mach_port_t port, natural_t type,
740 	    void * reference, vm_size_t referenceSize,
741 	    bool clientIs64 );
742 	virtual void free() APPLE_KEXT_OVERRIDE;
743 	void invalidatePort(void);
744 
745 	static bool _handler( void * target,
746 	    void * ref, IOService * newService, IONotifier * notifier );
747 	virtual bool handler( void * ref, IOService * newService );
748 
749 	virtual OSObject * getNextObject() APPLE_KEXT_OVERRIDE;
750 	virtual OSObject * copyNextObject() APPLE_KEXT_OVERRIDE;
751 };
752 
753 class IOServiceMessageUserNotification : public IOUserNotification
754 {
755 	OSDeclareDefaultStructors(IOServiceMessageUserNotification);
756 
757 	struct PingMsg {
758 		mach_msg_header_t               msgHdr;
759 		mach_msg_body_t                 msgBody;
760 		mach_msg_port_descriptor_t      ports[1];
761 		OSNotificationHeader64          notifyHeader __attribute__ ((packed));
762 	};
763 
764 	ipc_port_t          remotePort;
765 	void                *msgReference;
766 	mach_msg_size_t     msgReferenceSize;
767 	mach_msg_size_t     msgExtraSize;
768 	natural_t           msgType;
769 	uint8_t             clientIs64;
770 	int                 owningPID;
771 	bool                ipcLogged;
772 
773 public:
774 
775 	virtual bool init( mach_port_t port, natural_t type,
776 	    void * reference, vm_size_t referenceSize,
777 	    bool clientIs64 );
778 
779 	virtual void free() APPLE_KEXT_OVERRIDE;
780 	void invalidatePort(void);
781 
782 	static IOReturn _handler( void * target, void * ref,
783 	    UInt32 messageType, IOService * provider,
784 	    void * messageArgument, vm_size_t argSize );
785 	virtual IOReturn handler( void * ref,
786 	    UInt32 messageType, IOService * provider,
787 	    void * messageArgument, vm_size_t argSize );
788 
789 	virtual OSObject * getNextObject() APPLE_KEXT_OVERRIDE;
790 	virtual OSObject * copyNextObject() APPLE_KEXT_OVERRIDE;
791 };
792 
793 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
794 
795 #undef super
796 #define super IOUserIterator
797 OSDefineMetaClass( IOUserNotification, IOUserIterator );
798 OSDefineAbstractStructors( IOUserNotification, IOUserIterator );
799 
800 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
801 
802 void
free(void)803 IOUserNotification::free( void )
804 {
805 #if DEVELOPMENT || DEBUG
806 	IOLockLock( gIOObjectPortLock);
807 
808 	assert(userIteratorObject == NULL);
809 
810 	IOLockUnlock( gIOObjectPortLock);
811 #endif /* DEVELOPMENT || DEBUG */
812 
813 	super::free();
814 }
815 
816 
817 void
setNotification(IONotifier * notify)818 IOUserNotification::setNotification( IONotifier * notify )
819 {
820 	OSObject * previousNotify;
821 
822 	/*
823 	 * We must retain this object here before proceeding.
824 	 * Two threads may race in setNotification(). If one thread sets a new notifier while the
825 	 * other thread sets the notifier to NULL, it is possible for the second thread to call release()
826 	 * before the first thread calls retain(). Without the retain here, this thread interleaving
827 	 * would cause the object to get released and freed before it is retained by the first thread,
828 	 * which is a UaF.
829 	 */
830 	retain();
831 
832 	IOLockLock( gIOObjectPortLock);
833 
834 	previousNotify = userIteratorObject;
835 	userIteratorObject = notify;
836 
837 	IOLockUnlock( gIOObjectPortLock);
838 
839 	if (previousNotify) {
840 		assert(OSDynamicCast(IONotifier, previousNotify));
841 		((IONotifier *)previousNotify)->remove();
842 
843 		if (notify == NULL) {
844 			release();
845 		}
846 	} else if (notify) {
847 		// new IONotifier, retain the object. release() will happen in setNotification(NULL)
848 		retain();
849 	}
850 
851 	release(); // paired with retain() at beginning of this method
852 }
853 
854 void
reset()855 IOUserNotification::reset()
856 {
857 	// ?
858 }
859 
860 bool
isValid()861 IOUserNotification::isValid()
862 {
863 	return true;
864 }
865 
866 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
867 
868 #undef super
869 #define super IOUserNotification
OSDefineMetaClassAndStructors(IOServiceUserNotification,IOUserNotification)870 OSDefineMetaClassAndStructors(IOServiceUserNotification, IOUserNotification)
871 
872 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
873 
874 bool
875 IOServiceUserNotification::init( mach_port_t port, natural_t type,
876     void * reference, vm_size_t referenceSize,
877     bool clientIs64 )
878 {
879 	if (!super::init()) {
880 		return false;
881 	}
882 
883 	newSet = OSArray::withCapacity( 1 );
884 	if (!newSet) {
885 		return false;
886 	}
887 
888 	if (referenceSize > sizeof(OSAsyncReference64)) {
889 		return false;
890 	}
891 
892 	msgReferenceSize = mach_round_msg((mach_msg_size_t)referenceSize);
893 	msgReference = IOMallocZeroData(msgReferenceSize);
894 	if (!msgReference) {
895 		return false;
896 	}
897 
898 	remotePort = port;
899 	msgType = type;
900 	bcopy( reference, msgReference, referenceSize );
901 
902 	return true;
903 }
904 
905 void
invalidatePort(void)906 IOServiceUserNotification::invalidatePort(void)
907 {
908 	remotePort = MACH_PORT_NULL;
909 }
910 
911 void
free(void)912 IOServiceUserNotification::free( void )
913 {
914 	if (remotePort) {
915 		iokit_release_port_send(remotePort);
916 	}
917 	IOFreeData(msgReference, msgReferenceSize);
918 	OSSafeReleaseNULL(newSet);
919 
920 	super::free();
921 }
922 
923 bool
_handler(void * target,void * ref,IOService * newService,IONotifier * notifier)924 IOServiceUserNotification::_handler( void * target,
925     void * ref, IOService * newService, IONotifier * notifier )
926 {
927 	IOServiceUserNotification * targetObj = (IOServiceUserNotification *)target;
928 	bool ret;
929 
930 	targetObj->retain();
931 	ret = targetObj->handler( ref, newService );
932 	targetObj->release();
933 	return ret;
934 }
935 
936 bool
handler(void * ref,IOService * newService)937 IOServiceUserNotification::handler( void * ref,
938     IOService * newService )
939 {
940 	unsigned int        count;
941 	kern_return_t       kr;
942 	ipc_port_t          port = NULL;
943 	bool                sendPing = false;
944 	mach_msg_size_t     msgSize;
945 
946 	IOTakeLock( lock );
947 
948 	count = newSet->getCount();
949 	if (count < kMaxOutstanding) {
950 		newSet->setObject( newService );
951 		if ((sendPing = (armed && (0 == count)))) {
952 			armed = false;
953 		}
954 	}
955 
956 	IOUnlock( lock );
957 
958 	if (kIOServiceTerminatedNotificationType == msgType) {
959 		IOMachPort::setHoldDestroy( newService, IKOT_IOKIT_OBJECT );
960 	}
961 
962 	if (sendPing) {
963 		port = iokit_port_for_object( this, IKOT_IOKIT_OBJECT );
964 
965 		msgSize = (mach_msg_size_t)(sizeof(PingMsg) - sizeof(OSAsyncReference64) + msgReferenceSize);
966 		kr = kernel_mach_msg_send_with_builder(msgSize,
967 		    (MACH_SEND_MSG | MACH_SEND_ALWAYS | MACH_SEND_IMPORTANCE),
968 		    MACH_MSG_TIMEOUT_NONE, NULL,
969 		    ^(mach_msg_header_t *hdr, mach_msg_size_t size){
970 			PingMsg *thisMsg = (PingMsg *)hdr;
971 
972 			thisMsg->msgHdr.msgh_remote_port    = remotePort;
973 			thisMsg->msgHdr.msgh_local_port     = port;
974 			thisMsg->msgHdr.msgh_bits           = MACH_MSGH_BITS(
975 				MACH_MSG_TYPE_COPY_SEND /*remote*/,
976 				MACH_MSG_TYPE_MAKE_SEND /*local*/);
977 			thisMsg->msgHdr.msgh_size           = msgSize;
978 			thisMsg->msgHdr.msgh_id             = kOSNotificationMessageID;
979 
980 			thisMsg->notifyHeader.size          = 0;
981 			thisMsg->notifyHeader.type          = msgType;
982 
983 			bcopy( msgReference, thisMsg->notifyHeader.reference, msgReferenceSize );
984 		});
985 
986 		if (port) {
987 			iokit_release_port( port );
988 		}
989 
990 		if ((KERN_SUCCESS != kr) && !ipcLogged) {
991 			ipcLogged = true;
992 			IOLog("%s: kernel_mach_msg_send (0x%x)\n", __PRETTY_FUNCTION__, kr );
993 		}
994 	}
995 
996 	return true;
997 }
998 OSObject *
getNextObject()999 IOServiceUserNotification::getNextObject()
1000 {
1001 	assert(false);
1002 	return NULL;
1003 }
1004 
1005 OSObject *
copyNextObject()1006 IOServiceUserNotification::copyNextObject()
1007 {
1008 	unsigned int        count;
1009 	OSObject *          result;
1010 
1011 	IOLockLock(lock);
1012 
1013 	count = newSet->getCount();
1014 	if (count) {
1015 		result = newSet->getObject( count - 1 );
1016 		result->retain();
1017 		newSet->removeObject( count - 1);
1018 	} else {
1019 		result = NULL;
1020 		armed = true;
1021 	}
1022 
1023 	IOLockUnlock(lock);
1024 
1025 	return result;
1026 }
1027 
1028 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1029 
OSDefineMetaClassAndStructors(IOServiceMessageUserNotification,IOUserNotification)1030 OSDefineMetaClassAndStructors(IOServiceMessageUserNotification, IOUserNotification)
1031 
1032 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1033 
1034 bool
1035 IOServiceMessageUserNotification::init( mach_port_t port, natural_t type,
1036     void * reference, vm_size_t referenceSize, bool client64 )
1037 {
1038 	if (!super::init()) {
1039 		return false;
1040 	}
1041 
1042 	if (referenceSize > sizeof(OSAsyncReference64)) {
1043 		return false;
1044 	}
1045 
1046 	clientIs64 = client64;
1047 
1048 	owningPID = proc_selfpid();
1049 
1050 	msgReferenceSize = mach_round_msg((mach_msg_size_t)referenceSize);
1051 	msgReference = IOMallocZeroData(msgReferenceSize);
1052 	if (!msgReference) {
1053 		return false;
1054 	}
1055 
1056 	remotePort = port;
1057 	msgType = type;
1058 	bcopy( reference, msgReference, referenceSize );
1059 
1060 	return true;
1061 }
1062 
1063 void
invalidatePort(void)1064 IOServiceMessageUserNotification::invalidatePort(void)
1065 {
1066 	remotePort = MACH_PORT_NULL;
1067 }
1068 
1069 void
free(void)1070 IOServiceMessageUserNotification::free( void )
1071 {
1072 	if (remotePort) {
1073 		iokit_release_port_send(remotePort);
1074 	}
1075 	IOFreeData(msgReference, msgReferenceSize);
1076 
1077 	super::free();
1078 }
1079 
1080 IOReturn
_handler(void * target,void * ref,UInt32 messageType,IOService * provider,void * argument,vm_size_t argSize)1081 IOServiceMessageUserNotification::_handler( void * target, void * ref,
1082     UInt32 messageType, IOService * provider,
1083     void * argument, vm_size_t argSize )
1084 {
1085 	IOServiceMessageUserNotification * targetObj = (IOServiceMessageUserNotification *)target;
1086 	IOReturn ret;
1087 
1088 	targetObj->retain();
1089 	ret = targetObj->handler(
1090 		ref, messageType, provider, argument, argSize);
1091 	targetObj->release();
1092 	return ret;
1093 }
1094 
1095 IOReturn
handler(void * ref,UInt32 messageType,IOService * provider,void * messageArgument,vm_size_t callerArgSize)1096 IOServiceMessageUserNotification::handler( void * ref,
1097     UInt32 messageType, IOService * provider,
1098     void * messageArgument, vm_size_t callerArgSize )
1099 {
1100 	kern_return_t                kr;
1101 	vm_size_t                    argSize;
1102 	mach_msg_size_t              thisMsgSize;
1103 	ipc_port_t                   thisPort, providerPort;
1104 
1105 	if (kIOMessageCopyClientID == messageType) {
1106 		*((void **) messageArgument) = OSNumber::withNumber(owningPID, 32);
1107 		return kIOReturnSuccess;
1108 	}
1109 
1110 	if (callerArgSize == 0) {
1111 		if (clientIs64) {
1112 			argSize = sizeof(io_user_reference_t);
1113 		} else {
1114 			argSize = sizeof(uint32_t);
1115 		}
1116 	} else {
1117 		if (callerArgSize > kIOUserNotifyMaxMessageSize) {
1118 			callerArgSize = kIOUserNotifyMaxMessageSize;
1119 		}
1120 		argSize = callerArgSize;
1121 	}
1122 
1123 	// adjust message size for ipc restrictions
1124 	natural_t type = msgType;
1125 	type &= ~(kIOKitNoticationMsgSizeMask << kIOKitNoticationTypeSizeAdjShift);
1126 	type |= ((argSize & kIOKitNoticationMsgSizeMask) << kIOKitNoticationTypeSizeAdjShift);
1127 	argSize = (argSize + kIOKitNoticationMsgSizeMask) & ~kIOKitNoticationMsgSizeMask;
1128 
1129 	mach_msg_size_t extraSize = kIOUserNotifyMaxMessageSize + sizeof(IOServiceInterestContent64);
1130 	mach_msg_size_t msgSize = (mach_msg_size_t) (sizeof(PingMsg) - sizeof(OSAsyncReference64) + msgReferenceSize);
1131 
1132 	if (os_add3_overflow(msgSize, offsetof(IOServiceInterestContent64, messageArgument), argSize, &thisMsgSize)) {
1133 		return kIOReturnBadArgument;
1134 	}
1135 
1136 	providerPort = iokit_port_for_object( provider, IKOT_IOKIT_OBJECT );
1137 	thisPort = iokit_port_for_object( this, IKOT_IOKIT_OBJECT );
1138 
1139 	kr = kernel_mach_msg_send_with_builder(thisMsgSize,
1140 	    (MACH_SEND_MSG | MACH_SEND_ALWAYS | MACH_SEND_IMPORTANCE),
1141 	    MACH_MSG_TIMEOUT_NONE, NULL,
1142 	    ^(mach_msg_header_t *hdr, mach_msg_size_t size) {
1143 		PingMsg *thisMsg = (PingMsg *)hdr;
1144 		IOServiceInterestContent64 * data;
1145 
1146 		thisMsg->msgHdr.msgh_remote_port    = remotePort;
1147 		thisMsg->msgHdr.msgh_local_port     = thisPort;
1148 		thisMsg->msgHdr.msgh_bits           = MACH_MSGH_BITS_COMPLEX
1149 		|  MACH_MSGH_BITS(
1150 			MACH_MSG_TYPE_COPY_SEND /*remote*/,
1151 			MACH_MSG_TYPE_MAKE_SEND /*local*/);
1152 		thisMsg->msgHdr.msgh_size           = size;
1153 		thisMsg->msgHdr.msgh_id             = kOSNotificationMessageID;
1154 
1155 		thisMsg->msgBody.msgh_descriptor_count = 1;
1156 
1157 		thisMsg->ports[0].name              = providerPort;
1158 		thisMsg->ports[0].disposition       = MACH_MSG_TYPE_MAKE_SEND;
1159 		thisMsg->ports[0].type              = MACH_MSG_PORT_DESCRIPTOR;
1160 
1161 		thisMsg->notifyHeader.size          = extraSize;
1162 		thisMsg->notifyHeader.type          = type;
1163 		bcopy( msgReference, thisMsg->notifyHeader.reference, msgReferenceSize );
1164 
1165 
1166 		data = (IOServiceInterestContent64 *) (((uint8_t *) thisMsg) + msgSize);
1167 		// == thisMsg->notifyHeader.content;
1168 		data->messageType = messageType;
1169 
1170 		if (callerArgSize == 0) {
1171 		        data->messageArgument[0] = (io_user_reference_t) messageArgument;
1172 		        if (!clientIs64) {
1173 		                data->messageArgument[0] |= (data->messageArgument[0] << 32);
1174 			}
1175 		} else {
1176 		        bcopy( messageArgument, data->messageArgument, callerArgSize );
1177 		}
1178 	});
1179 
1180 	if (thisPort) {
1181 		iokit_release_port( thisPort );
1182 	}
1183 	if (providerPort) {
1184 		iokit_release_port( providerPort );
1185 	}
1186 
1187 	if (kr == MACH_SEND_NO_BUFFER) {
1188 		return kIOReturnNoMemory;
1189 	}
1190 
1191 	if ((KERN_SUCCESS != kr) && !ipcLogged) {
1192 		ipcLogged = true;
1193 		IOLog("%s: kernel_mach_msg_send (0x%x)\n", __PRETTY_FUNCTION__, kr );
1194 	}
1195 
1196 	return kIOReturnSuccess;
1197 }
1198 
1199 OSObject *
getNextObject()1200 IOServiceMessageUserNotification::getNextObject()
1201 {
1202 	return NULL;
1203 }
1204 
1205 OSObject *
copyNextObject()1206 IOServiceMessageUserNotification::copyNextObject()
1207 {
1208 	return NULL;
1209 }
1210 
1211 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1212 
1213 #undef super
1214 #define super IOService
1215 OSDefineMetaClassAndAbstractStructors( IOUserClient, IOService )
1216 
1217 IOLock       * gIOUserClientOwnersLock;
1218 
1219 void
initialize(void)1220 IOUserClient::initialize( void )
1221 {
1222 	gIOObjectPortLock       = IOLockAlloc();
1223 	gIOUserClientOwnersLock = IOLockAlloc();
1224 	gIOUserServerLock       = IOLockAlloc();
1225 	assert(gIOObjectPortLock && gIOUserClientOwnersLock);
1226 
1227 #if IOTRACKING
1228 	IOTrackingQueueCollectUser(IOUserIterator::gMetaClass.getTracking());
1229 	IOTrackingQueueCollectUser(IOServiceMessageUserNotification::gMetaClass.getTracking());
1230 	IOTrackingQueueCollectUser(IOServiceUserNotification::gMetaClass.getTracking());
1231 	IOTrackingQueueCollectUser(IOUserClient::gMetaClass.getTracking());
1232 	IOTrackingQueueCollectUser(IOMachPort::gMetaClass.getTracking());
1233 #endif /* IOTRACKING */
1234 }
1235 
1236 void
1237 #if __LP64__
1238 __attribute__((__noreturn__))
1239 #endif
setAsyncReference(OSAsyncReference asyncRef,mach_port_t wakePort,void * callback,void * refcon)1240 IOUserClient::setAsyncReference(OSAsyncReference asyncRef,
1241     mach_port_t wakePort,
1242     void *callback, void *refcon)
1243 {
1244 #if __LP64__
1245 	panic("setAsyncReference not valid for 64b");
1246 #else
1247 	asyncRef[kIOAsyncReservedIndex]      = ((uintptr_t) wakePort)
1248 	    | (kIOUCAsync0Flags & asyncRef[kIOAsyncReservedIndex]);
1249 	asyncRef[kIOAsyncCalloutFuncIndex]   = (uintptr_t) callback;
1250 	asyncRef[kIOAsyncCalloutRefconIndex] = (uintptr_t) refcon;
1251 #endif
1252 }
1253 
1254 void
setAsyncReference64(OSAsyncReference64 asyncRef,mach_port_t wakePort,mach_vm_address_t callback,io_user_reference_t refcon)1255 IOUserClient::setAsyncReference64(OSAsyncReference64 asyncRef,
1256     mach_port_t wakePort,
1257     mach_vm_address_t callback, io_user_reference_t refcon)
1258 {
1259 	asyncRef[kIOAsyncReservedIndex]      = ((io_user_reference_t) wakePort)
1260 	    | (kIOUCAsync0Flags & asyncRef[kIOAsyncReservedIndex]);
1261 	asyncRef[kIOAsyncCalloutFuncIndex]   = (io_user_reference_t) callback;
1262 	asyncRef[kIOAsyncCalloutRefconIndex] = refcon;
1263 }
1264 
1265 void
setAsyncReference64(OSAsyncReference64 asyncRef,mach_port_t wakePort,mach_vm_address_t callback,io_user_reference_t refcon,task_t task)1266 IOUserClient::setAsyncReference64(OSAsyncReference64 asyncRef,
1267     mach_port_t wakePort,
1268     mach_vm_address_t callback, io_user_reference_t refcon, task_t task)
1269 {
1270 	setAsyncReference64(asyncRef, wakePort, callback, refcon);
1271 	if (vm_map_is_64bit(get_task_map(task))) {
1272 		asyncRef[kIOAsyncReservedIndex] |= kIOUCAsync64Flag;
1273 	}
1274 }
1275 
1276 static OSDictionary *
CopyConsoleUser(UInt32 uid)1277 CopyConsoleUser(UInt32 uid)
1278 {
1279 	OSArray * array;
1280 	OSDictionary * user = NULL;
1281 
1282 	OSObject * ioProperty = IORegistryEntry::getRegistryRoot()->copyProperty(gIOConsoleUsersKey);
1283 	if ((array = OSDynamicCast(OSArray, ioProperty))) {
1284 		for (unsigned int idx = 0;
1285 		    (user = OSDynamicCast(OSDictionary, array->getObject(idx)));
1286 		    idx++) {
1287 			OSNumber * num;
1288 
1289 			if ((num = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionUIDKey)))
1290 			    && (uid == num->unsigned32BitValue())) {
1291 				user->retain();
1292 				break;
1293 			}
1294 		}
1295 	}
1296 	OSSafeReleaseNULL(ioProperty);
1297 	return user;
1298 }
1299 
1300 static OSDictionary *
CopyUserOnConsole(void)1301 CopyUserOnConsole(void)
1302 {
1303 	OSArray * array;
1304 	OSDictionary * user = NULL;
1305 
1306 	OSObject * ioProperty = IORegistryEntry::getRegistryRoot()->copyProperty(gIOConsoleUsersKey);
1307 	if ((array = OSDynamicCast(OSArray, ioProperty))) {
1308 		for (unsigned int idx = 0;
1309 		    (user = OSDynamicCast(OSDictionary, array->getObject(idx)));
1310 		    idx++) {
1311 			if (kOSBooleanTrue == user->getObject(gIOConsoleSessionOnConsoleKey)) {
1312 				user->retain();
1313 				break;
1314 			}
1315 		}
1316 	}
1317 	OSSafeReleaseNULL(ioProperty);
1318 	return user;
1319 }
1320 
1321 IOReturn
clientHasAuthorization(task_t task,IOService * service)1322 IOUserClient::clientHasAuthorization( task_t task,
1323     IOService * service )
1324 {
1325 	proc_t p;
1326 
1327 	p = (proc_t) get_bsdtask_info(task);
1328 	if (p) {
1329 		uint64_t authorizationID;
1330 
1331 		authorizationID = proc_uniqueid(p);
1332 		if (authorizationID) {
1333 			if (service->getAuthorizationID() == authorizationID) {
1334 				return kIOReturnSuccess;
1335 			}
1336 		}
1337 	}
1338 
1339 	return kIOReturnNotPermitted;
1340 }
1341 
1342 IOReturn
clientHasPrivilege(void * securityToken,const char * privilegeName)1343 IOUserClient::clientHasPrivilege( void * securityToken,
1344     const char * privilegeName )
1345 {
1346 	kern_return_t           kr;
1347 	security_token_t        token;
1348 	mach_msg_type_number_t  count;
1349 	task_t                  task;
1350 	OSDictionary *          user;
1351 	bool                    secureConsole;
1352 
1353 
1354 	if (!strncmp(privilegeName, kIOClientPrivilegeForeground,
1355 	    sizeof(kIOClientPrivilegeForeground))) {
1356 		if (task_is_gpu_denied(current_task())) {
1357 			return kIOReturnNotPrivileged;
1358 		} else {
1359 			return kIOReturnSuccess;
1360 		}
1361 	}
1362 
1363 	if (!strncmp(privilegeName, kIOClientPrivilegeConsoleSession,
1364 	    sizeof(kIOClientPrivilegeConsoleSession))) {
1365 		kauth_cred_t cred;
1366 		proc_t       p;
1367 
1368 		task = (task_t) securityToken;
1369 		if (!task) {
1370 			task = current_task();
1371 		}
1372 		p = (proc_t) get_bsdtask_info(task);
1373 		kr = kIOReturnNotPrivileged;
1374 
1375 		if (p && (cred = kauth_cred_proc_ref(p))) {
1376 			user = CopyUserOnConsole();
1377 			if (user) {
1378 				OSNumber * num;
1379 				if ((num = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionAuditIDKey)))
1380 				    && (cred->cr_audit.as_aia_p->ai_asid == (au_asid_t) num->unsigned32BitValue())) {
1381 					kr = kIOReturnSuccess;
1382 				}
1383 				user->release();
1384 			}
1385 			kauth_cred_unref(&cred);
1386 		}
1387 		return kr;
1388 	}
1389 
1390 	if ((secureConsole = !strncmp(privilegeName, kIOClientPrivilegeSecureConsoleProcess,
1391 	    sizeof(kIOClientPrivilegeSecureConsoleProcess)))) {
1392 		task = (task_t)((IOUCProcessToken *)securityToken)->token;
1393 	} else {
1394 		task = (task_t)securityToken;
1395 	}
1396 
1397 	count = TASK_SECURITY_TOKEN_COUNT;
1398 	kr = task_info( task, TASK_SECURITY_TOKEN, (task_info_t) &token, &count );
1399 
1400 	if (KERN_SUCCESS != kr) {
1401 	} else if (!strncmp(privilegeName, kIOClientPrivilegeAdministrator,
1402 	    sizeof(kIOClientPrivilegeAdministrator))) {
1403 		if (0 != token.val[0]) {
1404 			kr = kIOReturnNotPrivileged;
1405 		}
1406 	} else if (!strncmp(privilegeName, kIOClientPrivilegeLocalUser,
1407 	    sizeof(kIOClientPrivilegeLocalUser))) {
1408 		user = CopyConsoleUser(token.val[0]);
1409 		if (user) {
1410 			user->release();
1411 		} else {
1412 			kr = kIOReturnNotPrivileged;
1413 		}
1414 	} else if (secureConsole || !strncmp(privilegeName, kIOClientPrivilegeConsoleUser,
1415 	    sizeof(kIOClientPrivilegeConsoleUser))) {
1416 		user = CopyConsoleUser(token.val[0]);
1417 		if (user) {
1418 			if (user->getObject(gIOConsoleSessionOnConsoleKey) != kOSBooleanTrue) {
1419 				kr = kIOReturnNotPrivileged;
1420 			} else if (secureConsole) {
1421 				OSNumber * pid = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionSecureInputPIDKey));
1422 				if (pid && pid->unsigned32BitValue() != ((IOUCProcessToken *)securityToken)->pid) {
1423 					kr = kIOReturnNotPrivileged;
1424 				}
1425 			}
1426 			user->release();
1427 		} else {
1428 			kr = kIOReturnNotPrivileged;
1429 		}
1430 	} else {
1431 		kr = kIOReturnUnsupported;
1432 	}
1433 
1434 	return kr;
1435 }
1436 
1437 OSDictionary *
copyClientEntitlements(task_t task)1438 IOUserClient::copyClientEntitlements(task_t task)
1439 {
1440 	proc_t p = NULL;
1441 	pid_t pid = 0;
1442 	OSDictionary *entitlements = NULL;
1443 
1444 	p = (proc_t)get_bsdtask_info(task);
1445 	if (p == NULL) {
1446 		return NULL;
1447 	}
1448 	pid = proc_pid(p);
1449 
1450 	if (cs_entitlements_dictionary_copy(p, (void **)&entitlements) == 0) {
1451 		if (entitlements) {
1452 			return entitlements;
1453 		}
1454 	}
1455 
1456 	// If the above fails, thats it
1457 	return NULL;
1458 }
1459 
1460 OSDictionary *
copyClientEntitlementsVnode(vnode_t vnode,off_t offset)1461 IOUserClient::copyClientEntitlementsVnode(vnode_t vnode, off_t offset)
1462 {
1463 	OSDictionary *entitlements = NULL;
1464 
1465 	if (cs_entitlements_dictionary_copy_vnode(vnode, offset, (void**)&entitlements) != 0) {
1466 		return NULL;
1467 	}
1468 	return entitlements;
1469 }
1470 
1471 OSObject *
copyClientEntitlement(task_t task,const char * entitlement)1472 IOUserClient::copyClientEntitlement( task_t task,
1473     const char * entitlement )
1474 {
1475 	OSDictionary *entitlements;
1476 	OSObject *value;
1477 
1478 	#if PMAP_CS_ENABLE && !CONFIG_X86_64_COMPAT
1479 	if (pmap_cs_enabled() && amfi->query_context_to_object) {
1480 		struct CEQueryContext queryCtx = {};
1481 		size_t entlen = strlen(entitlement);
1482 		CEQuery_t query = {
1483 			/*
1484 			 *       We only select the dict value, if it exists this we will get
1485 			 *       a value CEQueryContext back to points to pmap backed memory
1486 			 */
1487 			CESelectDictValueDynamic((const uint8_t*)entitlement, entlen)
1488 		};
1489 		if (task == current_task()) {
1490 			// NULL task means current task, which translated to the current pmap
1491 			if (!pmap_query_entitlements(NULL, query, 1, &queryCtx)) {
1492 				return NULL;
1493 			}
1494 		} else {
1495 			vm_map_t task_map = get_task_map_reference(task);
1496 			if (task_map) {
1497 				pmap_t pmap = vm_map_get_pmap(task_map);
1498 				if (!pmap || !pmap_query_entitlements(pmap, query, 1, &queryCtx)) {
1499 					vm_map_deallocate(task_map);
1500 					return NULL;
1501 				}
1502 				vm_map_deallocate(task_map);
1503 			}
1504 		}
1505 		value = (OSObject*)amfi->query_context_to_object(&queryCtx);
1506 		return value;
1507 	}
1508 	#endif
1509 
1510 	entitlements = copyClientEntitlements(task);
1511 	if (entitlements == NULL) {
1512 		return NULL;
1513 	}
1514 
1515 	/* Fetch the entitlement value from the dictionary. */
1516 	value = entitlements->getObject(entitlement);
1517 	if (value != NULL) {
1518 		value->retain();
1519 	}
1520 
1521 	entitlements->release();
1522 	return value;
1523 }
1524 
1525 OSObject *
copyClientEntitlementVnode(struct vnode * vnode,off_t offset,const char * entitlement)1526 IOUserClient::copyClientEntitlementVnode(
1527 	struct vnode *vnode,
1528 	off_t offset,
1529 	const char *entitlement)
1530 {
1531 	OSDictionary *entitlements;
1532 	OSObject *value;
1533 
1534 	entitlements = copyClientEntitlementsVnode(vnode, offset);
1535 	if (entitlements == NULL) {
1536 		return NULL;
1537 	}
1538 
1539 	/* Fetch the entitlement value from the dictionary. */
1540 	value = entitlements->getObject(entitlement);
1541 	if (value != NULL) {
1542 		value->retain();
1543 	}
1544 
1545 	entitlements->release();
1546 	return value;
1547 }
1548 
1549 bool
init()1550 IOUserClient::init()
1551 {
1552 	if (getPropertyTable() || super::init()) {
1553 		return reserve();
1554 	}
1555 
1556 	return false;
1557 }
1558 
1559 bool
init(OSDictionary * dictionary)1560 IOUserClient::init(OSDictionary * dictionary)
1561 {
1562 	if (getPropertyTable() || super::init(dictionary)) {
1563 		return reserve();
1564 	}
1565 
1566 	return false;
1567 }
1568 
1569 bool
initWithTask(task_t owningTask,void * securityID,UInt32 type)1570 IOUserClient::initWithTask(task_t owningTask,
1571     void * securityID,
1572     UInt32 type )
1573 {
1574 	if (getPropertyTable() || super::init()) {
1575 		return reserve();
1576 	}
1577 
1578 	return false;
1579 }
1580 
1581 bool
initWithTask(task_t owningTask,void * securityID,UInt32 type,OSDictionary * properties)1582 IOUserClient::initWithTask(task_t owningTask,
1583     void * securityID,
1584     UInt32 type,
1585     OSDictionary * properties )
1586 {
1587 	bool ok;
1588 
1589 	ok = super::init( properties );
1590 	ok &= initWithTask( owningTask, securityID, type );
1591 
1592 	return ok;
1593 }
1594 
1595 bool
reserve()1596 IOUserClient::reserve()
1597 {
1598 	if (!reserved) {
1599 		reserved = IOMallocType(ExpansionData);
1600 	}
1601 	setTerminateDefer(NULL, true);
1602 	IOStatisticsRegisterCounter();
1603 
1604 	return true;
1605 }
1606 
1607 struct IOUserClientOwner {
1608 	task_t         task;
1609 	queue_chain_t  taskLink;
1610 	IOUserClient * uc;
1611 	queue_chain_t  ucLink;
1612 };
1613 
1614 IOReturn
registerOwner(task_t task)1615 IOUserClient::registerOwner(task_t task)
1616 {
1617 	IOUserClientOwner * owner;
1618 	IOReturn            ret;
1619 	bool                newOwner;
1620 
1621 	IOLockLock(gIOUserClientOwnersLock);
1622 
1623 	newOwner = true;
1624 	ret = kIOReturnSuccess;
1625 
1626 	if (!owners.next) {
1627 		queue_init(&owners);
1628 	} else {
1629 		queue_iterate(&owners, owner, IOUserClientOwner *, ucLink)
1630 		{
1631 			if (task != owner->task) {
1632 				continue;
1633 			}
1634 			newOwner = false;
1635 			break;
1636 		}
1637 	}
1638 	if (newOwner) {
1639 		owner = IOMallocType(IOUserClientOwner);
1640 
1641 		owner->task = task;
1642 		owner->uc   = this;
1643 		queue_enter_first(&owners, owner, IOUserClientOwner *, ucLink);
1644 		queue_enter_first(task_io_user_clients(task), owner, IOUserClientOwner *, taskLink);
1645 		if (messageAppSuspended) {
1646 			task_set_message_app_suspended(task, true);
1647 		}
1648 	}
1649 
1650 	IOLockUnlock(gIOUserClientOwnersLock);
1651 
1652 	return ret;
1653 }
1654 
1655 void
noMoreSenders(void)1656 IOUserClient::noMoreSenders(void)
1657 {
1658 	IOUserClientOwner * owner;
1659 	IOUserClientOwner * iter;
1660 	queue_head_t      * taskque;
1661 	bool                hasMessageAppSuspended;
1662 
1663 	IOLockLock(gIOUserClientOwnersLock);
1664 
1665 	if (owners.next) {
1666 		while (!queue_empty(&owners)) {
1667 			owner = (IOUserClientOwner *)(void *) queue_first(&owners);
1668 			taskque = task_io_user_clients(owner->task);
1669 			queue_remove(taskque, owner, IOUserClientOwner *, taskLink);
1670 			hasMessageAppSuspended = false;
1671 			queue_iterate(taskque, iter, IOUserClientOwner *, taskLink) {
1672 				hasMessageAppSuspended = iter->uc->messageAppSuspended;
1673 				if (hasMessageAppSuspended) {
1674 					break;
1675 				}
1676 			}
1677 			task_set_message_app_suspended(owner->task, hasMessageAppSuspended);
1678 			queue_remove(&owners, owner, IOUserClientOwner *, ucLink);
1679 			IOFreeType(owner, IOUserClientOwner);
1680 		}
1681 		owners.next = owners.prev = NULL;
1682 	}
1683 
1684 	IOLockUnlock(gIOUserClientOwnersLock);
1685 }
1686 
1687 
1688 extern "C" void
iokit_task_app_suspended_changed(task_t task)1689 iokit_task_app_suspended_changed(task_t task)
1690 {
1691 	queue_head_t      * taskque;
1692 	IOUserClientOwner * owner;
1693 	OSSet             * set;
1694 
1695 	IOLockLock(gIOUserClientOwnersLock);
1696 
1697 	taskque = task_io_user_clients(task);
1698 	set = NULL;
1699 	queue_iterate(taskque, owner, IOUserClientOwner *, taskLink) {
1700 		if (!owner->uc->messageAppSuspended) {
1701 			continue;
1702 		}
1703 		if (!set) {
1704 			set = OSSet::withCapacity(4);
1705 			if (!set) {
1706 				break;
1707 			}
1708 		}
1709 		set->setObject(owner->uc);
1710 	}
1711 
1712 	IOLockUnlock(gIOUserClientOwnersLock);
1713 
1714 	if (set) {
1715 		set->iterateObjects(^bool (OSObject * obj) {
1716 			IOUserClient      * uc;
1717 
1718 			uc = (typeof(uc))obj;
1719 #if 0
1720 			{
1721 			        OSString          * str;
1722 			        str = IOCopyLogNameForPID(task_pid(task));
1723 			        IOLog("iokit_task_app_suspended_changed(%s) %s %d\n", str ? str->getCStringNoCopy() : "",
1724 			        uc->getName(), task_is_app_suspended(task));
1725 			        OSSafeReleaseNULL(str);
1726 			}
1727 #endif
1728 			uc->message(kIOMessageTaskAppSuspendedChange, NULL);
1729 
1730 			return false;
1731 		});
1732 		set->release();
1733 	}
1734 }
1735 
1736 extern "C" kern_return_t
iokit_task_terminate(task_t task)1737 iokit_task_terminate(task_t task)
1738 {
1739 	IOUserClientOwner * owner;
1740 	IOUserClient      * dead;
1741 	IOUserClient      * uc;
1742 	queue_head_t      * taskque;
1743 
1744 	IOLockLock(gIOUserClientOwnersLock);
1745 
1746 	taskque = task_io_user_clients(task);
1747 	dead = NULL;
1748 	while (!queue_empty(taskque)) {
1749 		owner = (IOUserClientOwner *)(void *) queue_first(taskque);
1750 		uc = owner->uc;
1751 		queue_remove(taskque, owner, IOUserClientOwner *, taskLink);
1752 		queue_remove(&uc->owners, owner, IOUserClientOwner *, ucLink);
1753 		if (queue_empty(&uc->owners)) {
1754 			uc->retain();
1755 			IOLog("destroying out of band connect for %s\n", uc->getName());
1756 			// now using the uc queue head as a singly linked queue,
1757 			// leaving .next as NULL to mark it empty
1758 			uc->owners.next = NULL;
1759 			uc->owners.prev = (queue_entry_t) dead;
1760 			dead = uc;
1761 		}
1762 		IOFreeType(owner, IOUserClientOwner);
1763 	}
1764 
1765 	IOLockUnlock(gIOUserClientOwnersLock);
1766 
1767 	while (dead) {
1768 		uc = dead;
1769 		dead = (IOUserClient *)(void *) dead->owners.prev;
1770 		uc->owners.prev = NULL;
1771 		if (uc->sharedInstance || !uc->closed) {
1772 			uc->clientDied();
1773 		}
1774 		uc->release();
1775 	}
1776 
1777 	return KERN_SUCCESS;
1778 }
1779 
1780 struct IOUCFilterPolicy {
1781 	task_t             task;
1782 	io_filter_policy_t filterPolicy;
1783 	IOUCFilterPolicy * next;
1784 };
1785 
1786 io_filter_policy_t
filterForTask(task_t task,io_filter_policy_t addFilterPolicy)1787 IOUserClient::filterForTask(task_t task, io_filter_policy_t addFilterPolicy)
1788 {
1789 	IOUCFilterPolicy * elem;
1790 	io_filter_policy_t filterPolicy;
1791 
1792 	filterPolicy = 0;
1793 	IOLockLock(filterLock);
1794 
1795 	for (elem = reserved->filterPolicies; elem && (elem->task != task); elem = elem->next) {
1796 	}
1797 
1798 	if (elem) {
1799 		if (addFilterPolicy) {
1800 			assert(addFilterPolicy == elem->filterPolicy);
1801 		}
1802 		filterPolicy = elem->filterPolicy;
1803 	} else if (addFilterPolicy) {
1804 		elem = IOMallocType(IOUCFilterPolicy);
1805 		elem->task               = task;
1806 		elem->filterPolicy       = addFilterPolicy;
1807 		elem->next               = reserved->filterPolicies;
1808 		reserved->filterPolicies = elem;
1809 		filterPolicy = addFilterPolicy;
1810 	}
1811 
1812 	IOLockUnlock(filterLock);
1813 	return filterPolicy;
1814 }
1815 
1816 void
free()1817 IOUserClient::free()
1818 {
1819 	if (mappings) {
1820 		mappings->release();
1821 	}
1822 	if (lock) {
1823 		IORWLockFree(lock);
1824 	}
1825 	if (filterLock) {
1826 		IOLockFree(filterLock);
1827 	}
1828 
1829 	IOStatisticsUnregisterCounter();
1830 
1831 	assert(!owners.next);
1832 	assert(!owners.prev);
1833 
1834 	if (reserved) {
1835 		IOUCFilterPolicy * elem;
1836 		IOUCFilterPolicy * nextElem;
1837 		for (elem = reserved->filterPolicies; elem; elem = nextElem) {
1838 			nextElem = elem->next;
1839 			if (elem->filterPolicy && gIOUCFilterCallbacks->io_filter_release) {
1840 				gIOUCFilterCallbacks->io_filter_release(elem->filterPolicy);
1841 			}
1842 			IOFreeType(elem, IOUCFilterPolicy);
1843 		}
1844 		IOFreeType(reserved, ExpansionData);
1845 	}
1846 
1847 	super::free();
1848 }
1849 
1850 IOReturn
clientDied(void)1851 IOUserClient::clientDied( void )
1852 {
1853 	IOReturn ret = kIOReturnNotReady;
1854 
1855 	if (sharedInstance || OSCompareAndSwap8(0, 1, &closed)) {
1856 		ret = clientClose();
1857 	}
1858 
1859 	return ret;
1860 }
1861 
1862 IOReturn
clientClose(void)1863 IOUserClient::clientClose( void )
1864 {
1865 	return kIOReturnUnsupported;
1866 }
1867 
1868 IOService *
getService(void)1869 IOUserClient::getService( void )
1870 {
1871 	return NULL;
1872 }
1873 
1874 IOReturn
registerNotificationPort(mach_port_t,UInt32,UInt32)1875 IOUserClient::registerNotificationPort(
1876 	mach_port_t     /* port */,
1877 	UInt32          /* type */,
1878 	UInt32          /* refCon */)
1879 {
1880 	return kIOReturnUnsupported;
1881 }
1882 
1883 IOReturn
registerNotificationPort(mach_port_t port,UInt32 type,io_user_reference_t refCon)1884 IOUserClient::registerNotificationPort(
1885 	mach_port_t port,
1886 	UInt32          type,
1887 	io_user_reference_t refCon)
1888 {
1889 	return registerNotificationPort(port, type, (UInt32) refCon);
1890 }
1891 
1892 IOReturn
getNotificationSemaphore(UInt32 notification_type,semaphore_t * semaphore)1893 IOUserClient::getNotificationSemaphore( UInt32 notification_type,
1894     semaphore_t * semaphore )
1895 {
1896 	return kIOReturnUnsupported;
1897 }
1898 
1899 IOReturn
connectClient(IOUserClient *)1900 IOUserClient::connectClient( IOUserClient * /* client */ )
1901 {
1902 	return kIOReturnUnsupported;
1903 }
1904 
1905 IOReturn
clientMemoryForType(UInt32 type,IOOptionBits * options,IOMemoryDescriptor ** memory)1906 IOUserClient::clientMemoryForType( UInt32 type,
1907     IOOptionBits * options,
1908     IOMemoryDescriptor ** memory )
1909 {
1910 	return kIOReturnUnsupported;
1911 }
1912 
1913 IOReturn
clientMemoryForType(UInt32 type,IOOptionBits * options,OSSharedPtr<IOMemoryDescriptor> & memory)1914 IOUserClient::clientMemoryForType( UInt32 type,
1915     IOOptionBits * options,
1916     OSSharedPtr<IOMemoryDescriptor>& memory )
1917 {
1918 	IOMemoryDescriptor* memoryRaw = nullptr;
1919 	IOReturn result = clientMemoryForType(type, options, &memoryRaw);
1920 	memory.reset(memoryRaw, OSNoRetain);
1921 	return result;
1922 }
1923 
1924 #if !__LP64__
1925 IOMemoryMap *
mapClientMemory(IOOptionBits type,task_t task,IOOptionBits mapFlags,IOVirtualAddress atAddress)1926 IOUserClient::mapClientMemory(
1927 	IOOptionBits            type,
1928 	task_t                  task,
1929 	IOOptionBits            mapFlags,
1930 	IOVirtualAddress        atAddress )
1931 {
1932 	return NULL;
1933 }
1934 #endif
1935 
1936 IOMemoryMap *
mapClientMemory64(IOOptionBits type,task_t task,IOOptionBits mapFlags,mach_vm_address_t atAddress)1937 IOUserClient::mapClientMemory64(
1938 	IOOptionBits            type,
1939 	task_t                  task,
1940 	IOOptionBits            mapFlags,
1941 	mach_vm_address_t       atAddress )
1942 {
1943 	IOReturn            err;
1944 	IOOptionBits        options = 0;
1945 	IOMemoryDescriptor * memory = NULL;
1946 	IOMemoryMap *       map = NULL;
1947 
1948 	err = clientMemoryForType((UInt32) type, &options, &memory );
1949 
1950 	if (memory && (kIOReturnSuccess == err)) {
1951 		FAKE_STACK_FRAME(getMetaClass());
1952 
1953 		options = (options & ~kIOMapUserOptionsMask)
1954 		    | (mapFlags & kIOMapUserOptionsMask);
1955 		map = memory->createMappingInTask( task, atAddress, options );
1956 		memory->release();
1957 
1958 		FAKE_STACK_FRAME_END();
1959 	}
1960 
1961 	return map;
1962 }
1963 
1964 IOReturn
exportObjectToClient(task_t task,OSObject * obj,io_object_t * clientObj)1965 IOUserClient::exportObjectToClient(task_t task,
1966     OSObject *obj, io_object_t *clientObj)
1967 {
1968 	mach_port_name_t    name;
1969 
1970 	name = IOMachPort::makeSendRightForTask( task, obj, IKOT_IOKIT_OBJECT );
1971 
1972 	*clientObj = (io_object_t)(uintptr_t) name;
1973 
1974 	if (obj) {
1975 		obj->release();
1976 	}
1977 
1978 	return kIOReturnSuccess;
1979 }
1980 
1981 IOReturn
copyPortNameForObjectInTask(task_t task,OSObject * obj,mach_port_name_t * port_name)1982 IOUserClient::copyPortNameForObjectInTask(task_t task,
1983     OSObject *obj, mach_port_name_t * port_name)
1984 {
1985 	mach_port_name_t    name;
1986 
1987 	name = IOMachPort::makeSendRightForTask( task, obj, IKOT_IOKIT_IDENT );
1988 
1989 	*(mach_port_name_t *) port_name = name;
1990 
1991 	return kIOReturnSuccess;
1992 }
1993 
1994 IOReturn
copyObjectForPortNameInTask(task_t task,mach_port_name_t port_name,OSObject ** obj)1995 IOUserClient::copyObjectForPortNameInTask(task_t task, mach_port_name_t port_name,
1996     OSObject **obj)
1997 {
1998 	OSObject * object;
1999 
2000 	object = iokit_lookup_object_with_port_name(port_name, IKOT_IOKIT_IDENT, task);
2001 
2002 	*obj = object;
2003 
2004 	return object ? kIOReturnSuccess : kIOReturnIPCError;
2005 }
2006 
2007 IOReturn
copyObjectForPortNameInTask(task_t task,mach_port_name_t port_name,OSSharedPtr<OSObject> & obj)2008 IOUserClient::copyObjectForPortNameInTask(task_t task, mach_port_name_t port_name,
2009     OSSharedPtr<OSObject>& obj)
2010 {
2011 	OSObject* objRaw = NULL;
2012 	IOReturn result = copyObjectForPortNameInTask(task, port_name, &objRaw);
2013 	obj.reset(objRaw, OSNoRetain);
2014 	return result;
2015 }
2016 
2017 IOReturn
adjustPortNameReferencesInTask(task_t task,mach_port_name_t port_name,mach_port_delta_t delta)2018 IOUserClient::adjustPortNameReferencesInTask(task_t task, mach_port_name_t port_name, mach_port_delta_t delta)
2019 {
2020 	return iokit_mod_send_right(task, port_name, delta);
2021 }
2022 
2023 IOExternalMethod *
getExternalMethodForIndex(UInt32)2024 IOUserClient::getExternalMethodForIndex( UInt32 /* index */)
2025 {
2026 	return NULL;
2027 }
2028 
2029 IOExternalAsyncMethod *
getExternalAsyncMethodForIndex(UInt32)2030 IOUserClient::getExternalAsyncMethodForIndex( UInt32 /* index */)
2031 {
2032 	return NULL;
2033 }
2034 
2035 IOExternalTrap *
2036 IOUserClient::
getExternalTrapForIndex(UInt32 index)2037 getExternalTrapForIndex(UInt32 index)
2038 {
2039 	return NULL;
2040 }
2041 
2042 #pragma clang diagnostic push
2043 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
2044 
2045 // Suppressing the deprecated-declarations warning. Avoiding the use of deprecated
2046 // functions can break clients of kexts implementing getExternalMethodForIndex()
2047 IOExternalMethod *
2048 IOUserClient::
getTargetAndMethodForIndex(IOService ** targetP,UInt32 index)2049 getTargetAndMethodForIndex(IOService **targetP, UInt32 index)
2050 {
2051 	IOExternalMethod *method = getExternalMethodForIndex(index);
2052 
2053 	if (method) {
2054 		*targetP = (IOService *) method->object;
2055 	}
2056 
2057 	return method;
2058 }
2059 
2060 IOExternalMethod *
2061 IOUserClient::
getTargetAndMethodForIndex(OSSharedPtr<IOService> & targetP,UInt32 index)2062 getTargetAndMethodForIndex(OSSharedPtr<IOService>& targetP, UInt32 index)
2063 {
2064 	IOService* targetPRaw = NULL;
2065 	IOExternalMethod* result = getTargetAndMethodForIndex(&targetPRaw, index);
2066 	targetP.reset(targetPRaw, OSRetain);
2067 	return result;
2068 }
2069 
2070 IOExternalAsyncMethod *
2071 IOUserClient::
getAsyncTargetAndMethodForIndex(IOService ** targetP,UInt32 index)2072 getAsyncTargetAndMethodForIndex(IOService ** targetP, UInt32 index)
2073 {
2074 	IOExternalAsyncMethod *method = getExternalAsyncMethodForIndex(index);
2075 
2076 	if (method) {
2077 		*targetP = (IOService *) method->object;
2078 	}
2079 
2080 	return method;
2081 }
2082 
2083 IOExternalAsyncMethod *
2084 IOUserClient::
getAsyncTargetAndMethodForIndex(OSSharedPtr<IOService> & targetP,UInt32 index)2085 getAsyncTargetAndMethodForIndex(OSSharedPtr<IOService>& targetP, UInt32 index)
2086 {
2087 	IOService* targetPRaw = NULL;
2088 	IOExternalAsyncMethod* result = getAsyncTargetAndMethodForIndex(&targetPRaw, index);
2089 	targetP.reset(targetPRaw, OSRetain);
2090 	return result;
2091 }
2092 
2093 IOExternalTrap *
2094 IOUserClient::
getTargetAndTrapForIndex(IOService ** targetP,UInt32 index)2095 getTargetAndTrapForIndex(IOService ** targetP, UInt32 index)
2096 {
2097 	IOExternalTrap *trap = getExternalTrapForIndex(index);
2098 
2099 	if (trap) {
2100 		*targetP = trap->object;
2101 	}
2102 
2103 	return trap;
2104 }
2105 #pragma clang diagnostic pop
2106 
2107 IOReturn
releaseAsyncReference64(OSAsyncReference64 reference)2108 IOUserClient::releaseAsyncReference64(OSAsyncReference64 reference)
2109 {
2110 	mach_port_t port;
2111 	port = (mach_port_t) (reference[0] & ~kIOUCAsync0Flags);
2112 
2113 	if (MACH_PORT_NULL != port) {
2114 		iokit_release_port_send(port);
2115 	}
2116 
2117 	return kIOReturnSuccess;
2118 }
2119 
2120 IOReturn
releaseNotificationPort(mach_port_t port)2121 IOUserClient::releaseNotificationPort(mach_port_t port)
2122 {
2123 	if (MACH_PORT_NULL != port) {
2124 		iokit_release_port_send(port);
2125 	}
2126 
2127 	return kIOReturnSuccess;
2128 }
2129 
2130 IOReturn
sendAsyncResult(OSAsyncReference reference,IOReturn result,void * args[],UInt32 numArgs)2131 IOUserClient::sendAsyncResult(OSAsyncReference reference,
2132     IOReturn result, void *args[], UInt32 numArgs)
2133 {
2134 	OSAsyncReference64  reference64;
2135 	io_user_reference_t args64[kMaxAsyncArgs];
2136 	unsigned int        idx;
2137 
2138 	if (numArgs > kMaxAsyncArgs) {
2139 		return kIOReturnMessageTooLarge;
2140 	}
2141 
2142 	for (idx = 0; idx < kOSAsyncRef64Count; idx++) {
2143 		reference64[idx] = REF64(reference[idx]);
2144 	}
2145 
2146 	for (idx = 0; idx < numArgs; idx++) {
2147 		args64[idx] = REF64(args[idx]);
2148 	}
2149 
2150 	return sendAsyncResult64(reference64, result, args64, numArgs);
2151 }
2152 
2153 IOReturn
sendAsyncResult64WithOptions(OSAsyncReference64 reference,IOReturn result,io_user_reference_t args[],UInt32 numArgs,IOOptionBits options)2154 IOUserClient::sendAsyncResult64WithOptions(OSAsyncReference64 reference,
2155     IOReturn result, io_user_reference_t args[], UInt32 numArgs, IOOptionBits options)
2156 {
2157 	return _sendAsyncResult64(reference, result, args, numArgs, options);
2158 }
2159 
2160 IOReturn
sendAsyncResult64(OSAsyncReference64 reference,IOReturn result,io_user_reference_t args[],UInt32 numArgs)2161 IOUserClient::sendAsyncResult64(OSAsyncReference64 reference,
2162     IOReturn result, io_user_reference_t args[], UInt32 numArgs)
2163 {
2164 	return _sendAsyncResult64(reference, result, args, numArgs, 0);
2165 }
2166 
2167 IOReturn
_sendAsyncResult64(OSAsyncReference64 reference,IOReturn result,io_user_reference_t args[],UInt32 numArgs,IOOptionBits options)2168 IOUserClient::_sendAsyncResult64(OSAsyncReference64 reference,
2169     IOReturn result, io_user_reference_t args[], UInt32 numArgs, IOOptionBits options)
2170 {
2171 	struct ReplyMsg {
2172 		mach_msg_header_t msgHdr;
2173 		union{
2174 			struct{
2175 				OSNotificationHeader     notifyHdr;
2176 				IOAsyncCompletionContent asyncContent;
2177 				uint32_t                 args[kMaxAsyncArgs];
2178 			} msg32;
2179 			struct{
2180 				OSNotificationHeader64   notifyHdr;
2181 				IOAsyncCompletionContent asyncContent;
2182 				io_user_reference_t      args[kMaxAsyncArgs] __attribute__ ((packed));
2183 			} msg64;
2184 		} m;
2185 	};
2186 	ReplyMsg      replyMsg;
2187 	mach_port_t   replyPort;
2188 	kern_return_t kr;
2189 
2190 	// If no reply port, do nothing.
2191 	replyPort = (mach_port_t) (reference[0] & ~kIOUCAsync0Flags);
2192 	if (replyPort == MACH_PORT_NULL) {
2193 		return kIOReturnSuccess;
2194 	}
2195 
2196 	if (numArgs > kMaxAsyncArgs) {
2197 		return kIOReturnMessageTooLarge;
2198 	}
2199 
2200 	bzero(&replyMsg, sizeof(replyMsg));
2201 	replyMsg.msgHdr.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND /*remote*/,
2202 	    0 /*local*/);
2203 	replyMsg.msgHdr.msgh_remote_port = replyPort;
2204 	replyMsg.msgHdr.msgh_local_port  = NULL;
2205 	replyMsg.msgHdr.msgh_id          = kOSNotificationMessageID;
2206 	if (kIOUCAsync64Flag & reference[0]) {
2207 		replyMsg.msgHdr.msgh_size =
2208 		    sizeof(replyMsg.msgHdr) + sizeof(replyMsg.m.msg64)
2209 		    - (kMaxAsyncArgs - numArgs) * sizeof(io_user_reference_t);
2210 		replyMsg.m.msg64.notifyHdr.size = sizeof(IOAsyncCompletionContent)
2211 		    + numArgs * sizeof(io_user_reference_t);
2212 		replyMsg.m.msg64.notifyHdr.type = kIOAsyncCompletionNotificationType;
2213 		/* Copy reference except for reference[0], which is left as 0 from the earlier bzero */
2214 		bcopy(&reference[1], &replyMsg.m.msg64.notifyHdr.reference[1], sizeof(OSAsyncReference64) - sizeof(reference[0]));
2215 
2216 		replyMsg.m.msg64.asyncContent.result = result;
2217 		if (numArgs) {
2218 			bcopy(args, replyMsg.m.msg64.args, numArgs * sizeof(io_user_reference_t));
2219 		}
2220 	} else {
2221 		unsigned int idx;
2222 
2223 		replyMsg.msgHdr.msgh_size =
2224 		    sizeof(replyMsg.msgHdr) + sizeof(replyMsg.m.msg32)
2225 		    - (kMaxAsyncArgs - numArgs) * sizeof(uint32_t);
2226 
2227 		replyMsg.m.msg32.notifyHdr.size = sizeof(IOAsyncCompletionContent)
2228 		    + numArgs * sizeof(uint32_t);
2229 		replyMsg.m.msg32.notifyHdr.type = kIOAsyncCompletionNotificationType;
2230 
2231 		/* Skip reference[0] which is left as 0 from the earlier bzero */
2232 		for (idx = 1; idx < kOSAsyncRefCount; idx++) {
2233 			replyMsg.m.msg32.notifyHdr.reference[idx] = REF32(reference[idx]);
2234 		}
2235 
2236 		replyMsg.m.msg32.asyncContent.result = result;
2237 
2238 		for (idx = 0; idx < numArgs; idx++) {
2239 			replyMsg.m.msg32.args[idx] = REF32(args[idx]);
2240 		}
2241 	}
2242 
2243 	if ((options & kIOUserNotifyOptionCanDrop) != 0) {
2244 		kr = mach_msg_send_from_kernel_with_options( &replyMsg.msgHdr,
2245 		    replyMsg.msgHdr.msgh_size, MACH_SEND_TIMEOUT, MACH_MSG_TIMEOUT_NONE);
2246 	} else {
2247 		/* Fail on full queue. */
2248 		kr = mach_msg_send_from_kernel_proper( &replyMsg.msgHdr,
2249 		    replyMsg.msgHdr.msgh_size);
2250 	}
2251 	if ((KERN_SUCCESS != kr) && (MACH_SEND_TIMED_OUT != kr) && !(kIOUCAsyncErrorLoggedFlag & reference[0])) {
2252 		reference[0] |= kIOUCAsyncErrorLoggedFlag;
2253 		IOLog("%s: mach_msg_send_from_kernel_proper(0x%x)\n", __PRETTY_FUNCTION__, kr );
2254 	}
2255 	return kr;
2256 }
2257 
2258 
2259 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2260 
2261 extern "C" {
2262 #define CHECK(cls, obj, out)                      \
2263 	cls * out;                              \
2264 	if( !(out = OSDynamicCast( cls, obj)))  \
2265 	    return( kIOReturnBadArgument )
2266 
2267 #define CHECKLOCKED(cls, obj, out)                                        \
2268 	IOUserIterator * oIter;                                         \
2269 	cls * out;                                                      \
2270 	if( !(oIter = OSDynamicCast(IOUserIterator, obj)))              \
2271 	    return (kIOReturnBadArgument);                              \
2272 	if( !(out = OSDynamicCast(cls, oIter->userIteratorObject)))     \
2273 	    return (kIOReturnBadArgument)
2274 
2275 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2276 
2277 // Create a vm_map_copy_t or kalloc'ed data for memory
2278 // to be copied out. ipc will free after the copyout.
2279 
2280 static kern_return_t
copyoutkdata(const void * data,vm_size_t len,io_buf_ptr_t * buf)2281 copyoutkdata( const void * data, vm_size_t len,
2282     io_buf_ptr_t * buf )
2283 {
2284 	kern_return_t       err;
2285 	vm_map_copy_t       copy;
2286 
2287 	err = vm_map_copyin( kernel_map, CAST_USER_ADDR_T(data), len,
2288 	    false /* src_destroy */, &copy);
2289 
2290 	assert( err == KERN_SUCCESS );
2291 	if (err == KERN_SUCCESS) {
2292 		*buf = (char *) copy;
2293 	}
2294 
2295 	return err;
2296 }
2297 
2298 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2299 
2300 /* Routine io_server_version */
2301 kern_return_t
is_io_server_version(mach_port_t master_port,uint64_t * version)2302 is_io_server_version(
2303 	mach_port_t master_port,
2304 	uint64_t *version)
2305 {
2306 	*version = IOKIT_SERVER_VERSION;
2307 	return kIOReturnSuccess;
2308 }
2309 
2310 /* Routine io_object_get_class */
2311 kern_return_t
is_io_object_get_class(io_object_t object,io_name_t className)2312 is_io_object_get_class(
2313 	io_object_t object,
2314 	io_name_t className )
2315 {
2316 	const OSMetaClass* my_obj = NULL;
2317 
2318 	if (!object) {
2319 		return kIOReturnBadArgument;
2320 	}
2321 
2322 	my_obj = object->getMetaClass();
2323 	if (!my_obj) {
2324 		return kIOReturnNotFound;
2325 	}
2326 
2327 	strlcpy( className, my_obj->getClassName(), sizeof(io_name_t));
2328 
2329 	return kIOReturnSuccess;
2330 }
2331 
2332 /* Routine io_object_get_superclass */
2333 kern_return_t
is_io_object_get_superclass(mach_port_t master_port,io_name_t obj_name,io_name_t class_name)2334 is_io_object_get_superclass(
2335 	mach_port_t master_port,
2336 	io_name_t obj_name,
2337 	io_name_t class_name)
2338 {
2339 	IOReturn            ret;
2340 	const OSMetaClass * meta;
2341 	const OSMetaClass * super;
2342 	const OSSymbol    * name;
2343 	const char        * cstr;
2344 
2345 	if (!obj_name || !class_name) {
2346 		return kIOReturnBadArgument;
2347 	}
2348 	if (master_port != master_device_port) {
2349 		return kIOReturnNotPrivileged;
2350 	}
2351 
2352 	ret = kIOReturnNotFound;
2353 	meta = NULL;
2354 	do{
2355 		name = OSSymbol::withCString(obj_name);
2356 		if (!name) {
2357 			break;
2358 		}
2359 		OS_ANALYZER_SUPPRESS("77307290") meta = OSMetaClass::copyMetaClassWithName(name);
2360 		if (!meta) {
2361 			break;
2362 		}
2363 		super = meta->getSuperClass();
2364 		if (!super) {
2365 			break;
2366 		}
2367 		cstr = super->getClassName();
2368 		if (!cstr) {
2369 			break;
2370 		}
2371 		strlcpy(class_name, cstr, sizeof(io_name_t));
2372 		ret = kIOReturnSuccess;
2373 	}while (false);
2374 
2375 	OSSafeReleaseNULL(name);
2376 	if (meta) {
2377 		meta->releaseMetaClass();
2378 	}
2379 
2380 	return ret;
2381 }
2382 
2383 /* Routine io_object_get_bundle_identifier */
2384 kern_return_t
is_io_object_get_bundle_identifier(mach_port_t master_port,io_name_t obj_name,io_name_t bundle_name)2385 is_io_object_get_bundle_identifier(
2386 	mach_port_t master_port,
2387 	io_name_t obj_name,
2388 	io_name_t bundle_name)
2389 {
2390 	IOReturn            ret;
2391 	const OSMetaClass * meta;
2392 	const OSSymbol    * name;
2393 	const OSSymbol    * identifier;
2394 	const char        * cstr;
2395 
2396 	if (!obj_name || !bundle_name) {
2397 		return kIOReturnBadArgument;
2398 	}
2399 	if (master_port != master_device_port) {
2400 		return kIOReturnNotPrivileged;
2401 	}
2402 
2403 	ret = kIOReturnNotFound;
2404 	meta = NULL;
2405 	do{
2406 		name = OSSymbol::withCString(obj_name);
2407 		if (!name) {
2408 			break;
2409 		}
2410 		OS_ANALYZER_SUPPRESS("77307290") meta = OSMetaClass::copyMetaClassWithName(name);
2411 		if (!meta) {
2412 			break;
2413 		}
2414 		identifier = meta->getKmodName();
2415 		if (!identifier) {
2416 			break;
2417 		}
2418 		cstr = identifier->getCStringNoCopy();
2419 		if (!cstr) {
2420 			break;
2421 		}
2422 		strlcpy(bundle_name, identifier->getCStringNoCopy(), sizeof(io_name_t));
2423 		ret = kIOReturnSuccess;
2424 	}while (false);
2425 
2426 	OSSafeReleaseNULL(name);
2427 	if (meta) {
2428 		meta->releaseMetaClass();
2429 	}
2430 
2431 	return ret;
2432 }
2433 
2434 /* Routine io_object_conforms_to */
2435 kern_return_t
is_io_object_conforms_to(io_object_t object,io_name_t className,boolean_t * conforms)2436 is_io_object_conforms_to(
2437 	io_object_t object,
2438 	io_name_t className,
2439 	boolean_t *conforms )
2440 {
2441 	if (!object) {
2442 		return kIOReturnBadArgument;
2443 	}
2444 
2445 	*conforms = (NULL != object->metaCast( className ));
2446 
2447 	return kIOReturnSuccess;
2448 }
2449 
2450 /* Routine io_object_get_retain_count */
2451 kern_return_t
is_io_object_get_retain_count(io_object_t object,uint32_t * retainCount)2452 is_io_object_get_retain_count(
2453 	io_object_t object,
2454 	uint32_t *retainCount )
2455 {
2456 	if (!object) {
2457 		return kIOReturnBadArgument;
2458 	}
2459 
2460 	*retainCount = object->getRetainCount();
2461 	return kIOReturnSuccess;
2462 }
2463 
2464 /* Routine io_iterator_next */
2465 kern_return_t
is_io_iterator_next(io_object_t iterator,io_object_t * object)2466 is_io_iterator_next(
2467 	io_object_t iterator,
2468 	io_object_t *object )
2469 {
2470 	IOReturn    ret;
2471 	OSObject *  obj;
2472 	OSIterator * iter;
2473 	IOUserIterator * uiter;
2474 
2475 	if ((uiter = OSDynamicCast(IOUserIterator, iterator))) {
2476 		obj = uiter->copyNextObject();
2477 	} else if ((iter = OSDynamicCast(OSIterator, iterator))) {
2478 		obj = iter->getNextObject();
2479 		if (obj) {
2480 			obj->retain();
2481 		}
2482 	} else {
2483 		return kIOReturnBadArgument;
2484 	}
2485 
2486 	if (obj) {
2487 		*object = obj;
2488 		ret = kIOReturnSuccess;
2489 	} else {
2490 		ret = kIOReturnNoDevice;
2491 	}
2492 
2493 	return ret;
2494 }
2495 
2496 /* Routine io_iterator_reset */
2497 kern_return_t
is_io_iterator_reset(io_object_t iterator)2498 is_io_iterator_reset(
2499 	io_object_t iterator )
2500 {
2501 	CHECK( OSIterator, iterator, iter );
2502 
2503 	iter->reset();
2504 
2505 	return kIOReturnSuccess;
2506 }
2507 
2508 /* Routine io_iterator_is_valid */
2509 kern_return_t
is_io_iterator_is_valid(io_object_t iterator,boolean_t * is_valid)2510 is_io_iterator_is_valid(
2511 	io_object_t iterator,
2512 	boolean_t *is_valid )
2513 {
2514 	CHECK( OSIterator, iterator, iter );
2515 
2516 	*is_valid = iter->isValid();
2517 
2518 	return kIOReturnSuccess;
2519 }
2520 
2521 static kern_return_t
internal_io_service_match_property_table(io_service_t _service,const char * matching,mach_msg_type_number_t matching_size,boolean_t * matches)2522 internal_io_service_match_property_table(
2523 	io_service_t _service,
2524 	const char * matching,
2525 	mach_msg_type_number_t matching_size,
2526 	boolean_t *matches)
2527 {
2528 	CHECK( IOService, _service, service );
2529 
2530 	kern_return_t       kr;
2531 	OSObject *          obj;
2532 	OSDictionary *      dict;
2533 
2534 	assert(matching_size);
2535 
2536 
2537 	obj = OSUnserializeXML(matching, matching_size);
2538 
2539 	if ((dict = OSDynamicCast( OSDictionary, obj))) {
2540 		IOTaskRegistryCompatibilityMatching(current_task(), dict);
2541 		*matches = service->passiveMatch( dict );
2542 		kr = kIOReturnSuccess;
2543 	} else {
2544 		kr = kIOReturnBadArgument;
2545 	}
2546 
2547 	if (obj) {
2548 		obj->release();
2549 	}
2550 
2551 	return kr;
2552 }
2553 
2554 /* Routine io_service_match_property_table */
2555 kern_return_t
is_io_service_match_property_table(io_service_t service,io_string_t matching,boolean_t * matches)2556 is_io_service_match_property_table(
2557 	io_service_t service,
2558 	io_string_t matching,
2559 	boolean_t *matches )
2560 {
2561 	return kIOReturnUnsupported;
2562 }
2563 
2564 
2565 /* Routine io_service_match_property_table_ool */
2566 kern_return_t
is_io_service_match_property_table_ool(io_object_t service,io_buf_ptr_t matching,mach_msg_type_number_t matchingCnt,kern_return_t * result,boolean_t * matches)2567 is_io_service_match_property_table_ool(
2568 	io_object_t service,
2569 	io_buf_ptr_t matching,
2570 	mach_msg_type_number_t matchingCnt,
2571 	kern_return_t *result,
2572 	boolean_t *matches )
2573 {
2574 	kern_return_t         kr;
2575 	vm_offset_t           data;
2576 	vm_map_offset_t       map_data;
2577 
2578 	kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) matching );
2579 	data = CAST_DOWN(vm_offset_t, map_data);
2580 
2581 	if (KERN_SUCCESS == kr) {
2582 		// must return success after vm_map_copyout() succeeds
2583 		*result = internal_io_service_match_property_table(service,
2584 		    (const char *)data, matchingCnt, matches );
2585 		vm_deallocate( kernel_map, data, matchingCnt );
2586 	}
2587 
2588 	return kr;
2589 }
2590 
2591 /* Routine io_service_match_property_table_bin */
2592 kern_return_t
is_io_service_match_property_table_bin(io_object_t service,io_struct_inband_t matching,mach_msg_type_number_t matchingCnt,boolean_t * matches)2593 is_io_service_match_property_table_bin(
2594 	io_object_t service,
2595 	io_struct_inband_t matching,
2596 	mach_msg_type_number_t matchingCnt,
2597 	boolean_t *matches)
2598 {
2599 	return internal_io_service_match_property_table(service, matching, matchingCnt, matches);
2600 }
2601 
2602 static kern_return_t
internal_io_service_get_matching_services(mach_port_t master_port,const char * matching,mach_msg_type_number_t matching_size,io_iterator_t * existing)2603 internal_io_service_get_matching_services(
2604 	mach_port_t master_port,
2605 	const char * matching,
2606 	mach_msg_type_number_t matching_size,
2607 	io_iterator_t *existing )
2608 {
2609 	kern_return_t       kr;
2610 	OSObject *          obj;
2611 	OSDictionary *      dict;
2612 
2613 	if (master_port != master_device_port) {
2614 		return kIOReturnNotPrivileged;
2615 	}
2616 
2617 	assert(matching_size);
2618 	obj = OSUnserializeXML(matching, matching_size);
2619 
2620 	if ((dict = OSDynamicCast( OSDictionary, obj))) {
2621 		IOTaskRegistryCompatibilityMatching(current_task(), dict);
2622 		*existing = IOUserIterator::withIterator(IOService::getMatchingServices( dict ));
2623 		kr = kIOReturnSuccess;
2624 	} else {
2625 		kr = kIOReturnBadArgument;
2626 	}
2627 
2628 	if (obj) {
2629 		obj->release();
2630 	}
2631 
2632 	return kr;
2633 }
2634 
2635 /* Routine io_service_get_matching_services */
2636 kern_return_t
is_io_service_get_matching_services(mach_port_t master_port,io_string_t matching,io_iterator_t * existing)2637 is_io_service_get_matching_services(
2638 	mach_port_t master_port,
2639 	io_string_t matching,
2640 	io_iterator_t *existing )
2641 {
2642 	return kIOReturnUnsupported;
2643 }
2644 
2645 /* Routine io_service_get_matching_services_ool */
2646 kern_return_t
is_io_service_get_matching_services_ool(mach_port_t master_port,io_buf_ptr_t matching,mach_msg_type_number_t matchingCnt,kern_return_t * result,io_object_t * existing)2647 is_io_service_get_matching_services_ool(
2648 	mach_port_t master_port,
2649 	io_buf_ptr_t matching,
2650 	mach_msg_type_number_t matchingCnt,
2651 	kern_return_t *result,
2652 	io_object_t *existing )
2653 {
2654 	kern_return_t       kr;
2655 	vm_offset_t         data;
2656 	vm_map_offset_t     map_data;
2657 
2658 	kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) matching );
2659 	data = CAST_DOWN(vm_offset_t, map_data);
2660 
2661 	if (KERN_SUCCESS == kr) {
2662 		// must return success after vm_map_copyout() succeeds
2663 		// and mig will copy out objects on success
2664 		*existing = NULL;
2665 		*result = internal_io_service_get_matching_services(master_port,
2666 		    (const char *) data, matchingCnt, existing);
2667 		vm_deallocate( kernel_map, data, matchingCnt );
2668 	}
2669 
2670 	return kr;
2671 }
2672 
2673 /* Routine io_service_get_matching_services_bin */
2674 kern_return_t
is_io_service_get_matching_services_bin(mach_port_t master_port,io_struct_inband_t matching,mach_msg_type_number_t matchingCnt,io_object_t * existing)2675 is_io_service_get_matching_services_bin(
2676 	mach_port_t master_port,
2677 	io_struct_inband_t matching,
2678 	mach_msg_type_number_t matchingCnt,
2679 	io_object_t *existing)
2680 {
2681 	return internal_io_service_get_matching_services(master_port, matching, matchingCnt, existing);
2682 }
2683 
2684 
2685 static kern_return_t
internal_io_service_get_matching_service(mach_port_t master_port,const char * matching,mach_msg_type_number_t matching_size,io_service_t * service)2686 internal_io_service_get_matching_service(
2687 	mach_port_t master_port,
2688 	const char * matching,
2689 	mach_msg_type_number_t matching_size,
2690 	io_service_t *service )
2691 {
2692 	kern_return_t       kr;
2693 	OSObject *          obj;
2694 	OSDictionary *      dict;
2695 
2696 	if (master_port != master_device_port) {
2697 		return kIOReturnNotPrivileged;
2698 	}
2699 
2700 	assert(matching_size);
2701 	obj = OSUnserializeXML(matching, matching_size);
2702 
2703 	if ((dict = OSDynamicCast( OSDictionary, obj))) {
2704 		IOTaskRegistryCompatibilityMatching(current_task(), dict);
2705 		*service = IOService::copyMatchingService( dict );
2706 		kr = *service ? kIOReturnSuccess : kIOReturnNotFound;
2707 	} else {
2708 		kr = kIOReturnBadArgument;
2709 	}
2710 
2711 	if (obj) {
2712 		obj->release();
2713 	}
2714 
2715 	return kr;
2716 }
2717 
2718 /* Routine io_service_get_matching_service */
2719 kern_return_t
is_io_service_get_matching_service(mach_port_t master_port,io_string_t matching,io_service_t * service)2720 is_io_service_get_matching_service(
2721 	mach_port_t master_port,
2722 	io_string_t matching,
2723 	io_service_t *service )
2724 {
2725 	return kIOReturnUnsupported;
2726 }
2727 
2728 /* Routine io_service_get_matching_services_ool */
2729 kern_return_t
is_io_service_get_matching_service_ool(mach_port_t master_port,io_buf_ptr_t matching,mach_msg_type_number_t matchingCnt,kern_return_t * result,io_object_t * service)2730 is_io_service_get_matching_service_ool(
2731 	mach_port_t master_port,
2732 	io_buf_ptr_t matching,
2733 	mach_msg_type_number_t matchingCnt,
2734 	kern_return_t *result,
2735 	io_object_t *service )
2736 {
2737 	kern_return_t       kr;
2738 	vm_offset_t         data;
2739 	vm_map_offset_t     map_data;
2740 
2741 	kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) matching );
2742 	data = CAST_DOWN(vm_offset_t, map_data);
2743 
2744 	if (KERN_SUCCESS == kr) {
2745 		// must return success after vm_map_copyout() succeeds
2746 		// and mig will copy out objects on success
2747 		*service = NULL;
2748 		*result = internal_io_service_get_matching_service(master_port,
2749 		    (const char *) data, matchingCnt, service );
2750 		vm_deallocate( kernel_map, data, matchingCnt );
2751 	}
2752 
2753 	return kr;
2754 }
2755 
2756 /* Routine io_service_get_matching_service_bin */
2757 kern_return_t
is_io_service_get_matching_service_bin(mach_port_t master_port,io_struct_inband_t matching,mach_msg_type_number_t matchingCnt,io_object_t * service)2758 is_io_service_get_matching_service_bin(
2759 	mach_port_t master_port,
2760 	io_struct_inband_t matching,
2761 	mach_msg_type_number_t matchingCnt,
2762 	io_object_t *service)
2763 {
2764 	return internal_io_service_get_matching_service(master_port, matching, matchingCnt, service);
2765 }
2766 
2767 static kern_return_t
internal_io_service_add_notification(mach_port_t master_port,io_name_t notification_type,const char * matching,size_t matching_size,mach_port_t port,void * reference,vm_size_t referenceSize,bool client64,io_object_t * notification)2768 internal_io_service_add_notification(
2769 	mach_port_t master_port,
2770 	io_name_t notification_type,
2771 	const char * matching,
2772 	size_t matching_size,
2773 	mach_port_t port,
2774 	void * reference,
2775 	vm_size_t referenceSize,
2776 	bool client64,
2777 	io_object_t * notification )
2778 {
2779 	IOServiceUserNotification * userNotify = NULL;
2780 	IONotifier *                notify = NULL;
2781 	const OSSymbol *            sym;
2782 	OSObject *                  obj;
2783 	OSDictionary *              dict;
2784 	IOReturn                    err;
2785 	natural_t                   userMsgType;
2786 
2787 	if (master_port != master_device_port) {
2788 		return kIOReturnNotPrivileged;
2789 	}
2790 
2791 	do {
2792 		err = kIOReturnNoResources;
2793 
2794 		if (matching_size > (sizeof(io_struct_inband_t) * 1024)) {
2795 			return kIOReturnMessageTooLarge;
2796 		}
2797 
2798 		if (!(sym = OSSymbol::withCString( notification_type ))) {
2799 			err = kIOReturnNoResources;
2800 		}
2801 
2802 		assert(matching_size);
2803 		obj = OSUnserializeXML(matching, matching_size);
2804 		dict = OSDynamicCast(OSDictionary, obj);
2805 		if (!dict) {
2806 			err = kIOReturnBadArgument;
2807 			continue;
2808 		}
2809 		IOTaskRegistryCompatibilityMatching(current_task(), dict);
2810 
2811 		if ((sym == gIOPublishNotification)
2812 		    || (sym == gIOFirstPublishNotification)) {
2813 			userMsgType = kIOServicePublishNotificationType;
2814 		} else if ((sym == gIOMatchedNotification)
2815 		    || (sym == gIOFirstMatchNotification)) {
2816 			userMsgType = kIOServiceMatchedNotificationType;
2817 		} else if ((sym == gIOTerminatedNotification)
2818 		    || (sym == gIOWillTerminateNotification)) {
2819 			userMsgType = kIOServiceTerminatedNotificationType;
2820 		} else {
2821 			userMsgType = kLastIOKitNotificationType;
2822 		}
2823 
2824 		userNotify = new IOServiceUserNotification;
2825 
2826 		if (userNotify && !userNotify->init( port, userMsgType,
2827 		    reference, referenceSize, client64)) {
2828 			userNotify->release();
2829 			userNotify = NULL;
2830 		}
2831 		if (!userNotify) {
2832 			continue;
2833 		}
2834 
2835 		notify = IOService::addMatchingNotification( sym, dict,
2836 		    &userNotify->_handler, userNotify );
2837 		if (notify) {
2838 			*notification = userNotify;
2839 			userNotify->setNotification( notify );
2840 			err = kIOReturnSuccess;
2841 		} else {
2842 			err = kIOReturnUnsupported;
2843 		}
2844 	} while (false);
2845 
2846 	if ((kIOReturnSuccess != err) && userNotify) {
2847 		userNotify->setNotification(NULL);
2848 		userNotify->invalidatePort();
2849 		userNotify->release();
2850 		userNotify = NULL;
2851 	}
2852 
2853 	if (sym) {
2854 		sym->release();
2855 	}
2856 	if (obj) {
2857 		obj->release();
2858 	}
2859 
2860 	return err;
2861 }
2862 
2863 
2864 /* Routine io_service_add_notification */
2865 kern_return_t
is_io_service_add_notification(mach_port_t master_port,io_name_t notification_type,io_string_t matching,mach_port_t port,io_async_ref_t reference,mach_msg_type_number_t referenceCnt,io_object_t * notification)2866 is_io_service_add_notification(
2867 	mach_port_t master_port,
2868 	io_name_t notification_type,
2869 	io_string_t matching,
2870 	mach_port_t port,
2871 	io_async_ref_t reference,
2872 	mach_msg_type_number_t referenceCnt,
2873 	io_object_t * notification )
2874 {
2875 	return kIOReturnUnsupported;
2876 }
2877 
2878 /* Routine io_service_add_notification_64 */
2879 kern_return_t
is_io_service_add_notification_64(mach_port_t master_port,io_name_t notification_type,io_string_t matching,mach_port_t wake_port,io_async_ref64_t reference,mach_msg_type_number_t referenceCnt,io_object_t * notification)2880 is_io_service_add_notification_64(
2881 	mach_port_t master_port,
2882 	io_name_t notification_type,
2883 	io_string_t matching,
2884 	mach_port_t wake_port,
2885 	io_async_ref64_t reference,
2886 	mach_msg_type_number_t referenceCnt,
2887 	io_object_t *notification )
2888 {
2889 	return kIOReturnUnsupported;
2890 }
2891 
2892 /* Routine io_service_add_notification_bin */
2893 kern_return_t
is_io_service_add_notification_bin(mach_port_t master_port,io_name_t notification_type,io_struct_inband_t matching,mach_msg_type_number_t matchingCnt,mach_port_t wake_port,io_async_ref_t reference,mach_msg_type_number_t referenceCnt,io_object_t * notification)2894 is_io_service_add_notification_bin
2895 (
2896 	mach_port_t master_port,
2897 	io_name_t notification_type,
2898 	io_struct_inband_t matching,
2899 	mach_msg_type_number_t matchingCnt,
2900 	mach_port_t wake_port,
2901 	io_async_ref_t reference,
2902 	mach_msg_type_number_t referenceCnt,
2903 	io_object_t *notification)
2904 {
2905 	io_async_ref_t zreference;
2906 
2907 	if (referenceCnt > ASYNC_REF_COUNT) {
2908 		return kIOReturnBadArgument;
2909 	}
2910 	bcopy(&reference[0], &zreference[0], referenceCnt * sizeof(zreference[0]));
2911 	bzero(&zreference[referenceCnt], (ASYNC_REF_COUNT - referenceCnt) * sizeof(zreference[0]));
2912 
2913 	return internal_io_service_add_notification(master_port, notification_type,
2914 	           matching, matchingCnt, wake_port, &zreference[0], sizeof(io_async_ref_t),
2915 	           false, notification);
2916 }
2917 
2918 /* Routine io_service_add_notification_bin_64 */
2919 kern_return_t
is_io_service_add_notification_bin_64(mach_port_t master_port,io_name_t notification_type,io_struct_inband_t matching,mach_msg_type_number_t matchingCnt,mach_port_t wake_port,io_async_ref64_t reference,mach_msg_type_number_t referenceCnt,io_object_t * notification)2920 is_io_service_add_notification_bin_64
2921 (
2922 	mach_port_t master_port,
2923 	io_name_t notification_type,
2924 	io_struct_inband_t matching,
2925 	mach_msg_type_number_t matchingCnt,
2926 	mach_port_t wake_port,
2927 	io_async_ref64_t reference,
2928 	mach_msg_type_number_t referenceCnt,
2929 	io_object_t *notification)
2930 {
2931 	io_async_ref64_t zreference;
2932 
2933 	if (referenceCnt > ASYNC_REF64_COUNT) {
2934 		return kIOReturnBadArgument;
2935 	}
2936 	bcopy(&reference[0], &zreference[0], referenceCnt * sizeof(zreference[0]));
2937 	bzero(&zreference[referenceCnt], (ASYNC_REF64_COUNT - referenceCnt) * sizeof(zreference[0]));
2938 
2939 	return internal_io_service_add_notification(master_port, notification_type,
2940 	           matching, matchingCnt, wake_port, &zreference[0], sizeof(io_async_ref64_t),
2941 	           true, notification);
2942 }
2943 
2944 static kern_return_t
internal_io_service_add_notification_ool(mach_port_t master_port,io_name_t notification_type,io_buf_ptr_t matching,mach_msg_type_number_t matchingCnt,mach_port_t wake_port,void * reference,vm_size_t referenceSize,bool client64,kern_return_t * result,io_object_t * notification)2945 internal_io_service_add_notification_ool(
2946 	mach_port_t master_port,
2947 	io_name_t notification_type,
2948 	io_buf_ptr_t matching,
2949 	mach_msg_type_number_t matchingCnt,
2950 	mach_port_t wake_port,
2951 	void * reference,
2952 	vm_size_t referenceSize,
2953 	bool client64,
2954 	kern_return_t *result,
2955 	io_object_t *notification )
2956 {
2957 	kern_return_t       kr;
2958 	vm_offset_t         data;
2959 	vm_map_offset_t     map_data;
2960 
2961 	kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) matching );
2962 	data = CAST_DOWN(vm_offset_t, map_data);
2963 
2964 	if (KERN_SUCCESS == kr) {
2965 		// must return success after vm_map_copyout() succeeds
2966 		// and mig will copy out objects on success
2967 		*notification = NULL;
2968 		*result = internal_io_service_add_notification( master_port, notification_type,
2969 		    (char *) data, matchingCnt, wake_port, reference, referenceSize, client64, notification );
2970 		vm_deallocate( kernel_map, data, matchingCnt );
2971 	}
2972 
2973 	return kr;
2974 }
2975 
2976 /* Routine io_service_add_notification_ool */
2977 kern_return_t
is_io_service_add_notification_ool(mach_port_t master_port,io_name_t notification_type,io_buf_ptr_t matching,mach_msg_type_number_t matchingCnt,mach_port_t wake_port,io_async_ref_t reference,mach_msg_type_number_t referenceCnt,kern_return_t * result,io_object_t * notification)2978 is_io_service_add_notification_ool(
2979 	mach_port_t master_port,
2980 	io_name_t notification_type,
2981 	io_buf_ptr_t matching,
2982 	mach_msg_type_number_t matchingCnt,
2983 	mach_port_t wake_port,
2984 	io_async_ref_t reference,
2985 	mach_msg_type_number_t referenceCnt,
2986 	kern_return_t *result,
2987 	io_object_t *notification )
2988 {
2989 	io_async_ref_t zreference;
2990 
2991 	if (referenceCnt > ASYNC_REF_COUNT) {
2992 		return kIOReturnBadArgument;
2993 	}
2994 	bcopy(&reference[0], &zreference[0], referenceCnt * sizeof(zreference[0]));
2995 	bzero(&zreference[referenceCnt], (ASYNC_REF_COUNT - referenceCnt) * sizeof(zreference[0]));
2996 
2997 	return internal_io_service_add_notification_ool(master_port, notification_type,
2998 	           matching, matchingCnt, wake_port, &zreference[0], sizeof(io_async_ref_t),
2999 	           false, result, notification);
3000 }
3001 
3002 /* Routine io_service_add_notification_ool_64 */
3003 kern_return_t
is_io_service_add_notification_ool_64(mach_port_t master_port,io_name_t notification_type,io_buf_ptr_t matching,mach_msg_type_number_t matchingCnt,mach_port_t wake_port,io_async_ref64_t reference,mach_msg_type_number_t referenceCnt,kern_return_t * result,io_object_t * notification)3004 is_io_service_add_notification_ool_64(
3005 	mach_port_t master_port,
3006 	io_name_t notification_type,
3007 	io_buf_ptr_t matching,
3008 	mach_msg_type_number_t matchingCnt,
3009 	mach_port_t wake_port,
3010 	io_async_ref64_t reference,
3011 	mach_msg_type_number_t referenceCnt,
3012 	kern_return_t *result,
3013 	io_object_t *notification )
3014 {
3015 	io_async_ref64_t zreference;
3016 
3017 	if (referenceCnt > ASYNC_REF64_COUNT) {
3018 		return kIOReturnBadArgument;
3019 	}
3020 	bcopy(&reference[0], &zreference[0], referenceCnt * sizeof(zreference[0]));
3021 	bzero(&zreference[referenceCnt], (ASYNC_REF64_COUNT - referenceCnt) * sizeof(zreference[0]));
3022 
3023 	return internal_io_service_add_notification_ool(master_port, notification_type,
3024 	           matching, matchingCnt, wake_port, &zreference[0], sizeof(io_async_ref64_t),
3025 	           true, result, notification);
3026 }
3027 
3028 /* Routine io_service_add_notification_old */
3029 kern_return_t
is_io_service_add_notification_old(mach_port_t master_port,io_name_t notification_type,io_string_t matching,mach_port_t port,natural_t ref,io_object_t * notification)3030 is_io_service_add_notification_old(
3031 	mach_port_t master_port,
3032 	io_name_t notification_type,
3033 	io_string_t matching,
3034 	mach_port_t port,
3035 	// for binary compatibility reasons, this must be natural_t for ILP32
3036 	natural_t ref,
3037 	io_object_t * notification )
3038 {
3039 	return is_io_service_add_notification( master_port, notification_type,
3040 	           matching, port, &ref, 1, notification );
3041 }
3042 
3043 
3044 static kern_return_t
internal_io_service_add_interest_notification(io_object_t _service,io_name_t type_of_interest,mach_port_t port,void * reference,vm_size_t referenceSize,bool client64,io_object_t * notification)3045 internal_io_service_add_interest_notification(
3046 	io_object_t _service,
3047 	io_name_t type_of_interest,
3048 	mach_port_t port,
3049 	void * reference,
3050 	vm_size_t referenceSize,
3051 	bool client64,
3052 	io_object_t * notification )
3053 {
3054 	IOServiceMessageUserNotification *  userNotify = NULL;
3055 	IONotifier *                        notify = NULL;
3056 	const OSSymbol *                    sym;
3057 	IOReturn                            err;
3058 
3059 	CHECK( IOService, _service, service );
3060 
3061 	err = kIOReturnNoResources;
3062 	if ((sym = OSSymbol::withCString( type_of_interest ))) {
3063 		do {
3064 			userNotify = new IOServiceMessageUserNotification;
3065 
3066 			if (userNotify && !userNotify->init( port, kIOServiceMessageNotificationType,
3067 			    reference, referenceSize, client64 )) {
3068 				userNotify->release();
3069 				userNotify = NULL;
3070 			}
3071 			if (!userNotify) {
3072 				continue;
3073 			}
3074 
3075 			notify = service->registerInterest( sym,
3076 			    &userNotify->_handler, userNotify );
3077 			if (notify) {
3078 				*notification = userNotify;
3079 				userNotify->setNotification( notify );
3080 				err = kIOReturnSuccess;
3081 			} else {
3082 				err = kIOReturnUnsupported;
3083 			}
3084 		} while (false);
3085 
3086 		sym->release();
3087 	}
3088 
3089 	if ((kIOReturnSuccess != err) && userNotify) {
3090 		userNotify->setNotification(NULL);
3091 		userNotify->invalidatePort();
3092 		userNotify->release();
3093 		userNotify = NULL;
3094 	}
3095 
3096 	return err;
3097 }
3098 
3099 /* Routine io_service_add_message_notification */
3100 kern_return_t
is_io_service_add_interest_notification(io_object_t service,io_name_t type_of_interest,mach_port_t port,io_async_ref_t reference,mach_msg_type_number_t referenceCnt,io_object_t * notification)3101 is_io_service_add_interest_notification(
3102 	io_object_t service,
3103 	io_name_t type_of_interest,
3104 	mach_port_t port,
3105 	io_async_ref_t reference,
3106 	mach_msg_type_number_t referenceCnt,
3107 	io_object_t * notification )
3108 {
3109 	io_async_ref_t zreference;
3110 
3111 	if (referenceCnt > ASYNC_REF_COUNT) {
3112 		return kIOReturnBadArgument;
3113 	}
3114 	bcopy(&reference[0], &zreference[0], referenceCnt * sizeof(zreference[0]));
3115 	bzero(&zreference[referenceCnt], (ASYNC_REF_COUNT - referenceCnt) * sizeof(zreference[0]));
3116 
3117 	return internal_io_service_add_interest_notification(service, type_of_interest,
3118 	           port, &zreference[0], sizeof(io_async_ref_t), false, notification);
3119 }
3120 
3121 /* Routine io_service_add_interest_notification_64 */
3122 kern_return_t
is_io_service_add_interest_notification_64(io_object_t service,io_name_t type_of_interest,mach_port_t wake_port,io_async_ref64_t reference,mach_msg_type_number_t referenceCnt,io_object_t * notification)3123 is_io_service_add_interest_notification_64(
3124 	io_object_t service,
3125 	io_name_t type_of_interest,
3126 	mach_port_t wake_port,
3127 	io_async_ref64_t reference,
3128 	mach_msg_type_number_t referenceCnt,
3129 	io_object_t *notification )
3130 {
3131 	io_async_ref64_t zreference;
3132 
3133 	if (referenceCnt > ASYNC_REF64_COUNT) {
3134 		return kIOReturnBadArgument;
3135 	}
3136 	bcopy(&reference[0], &zreference[0], referenceCnt * sizeof(zreference[0]));
3137 	bzero(&zreference[referenceCnt], (ASYNC_REF64_COUNT - referenceCnt) * sizeof(zreference[0]));
3138 
3139 	return internal_io_service_add_interest_notification(service, type_of_interest,
3140 	           wake_port, &zreference[0], sizeof(io_async_ref64_t), true, notification);
3141 }
3142 
3143 
3144 /* Routine io_service_acknowledge_notification */
3145 kern_return_t
is_io_service_acknowledge_notification(io_object_t _service,natural_t notify_ref,natural_t response)3146 is_io_service_acknowledge_notification(
3147 	io_object_t _service,
3148 	natural_t notify_ref,
3149 	natural_t response )
3150 {
3151 	CHECK( IOService, _service, service );
3152 
3153 	return service->acknowledgeNotification((IONotificationRef)(uintptr_t) notify_ref,
3154 	           (IOOptionBits) response );
3155 }
3156 
3157 /* Routine io_connect_get_semaphore */
3158 kern_return_t
is_io_connect_get_notification_semaphore(io_connect_t connection,natural_t notification_type,semaphore_t * semaphore)3159 is_io_connect_get_notification_semaphore(
3160 	io_connect_t connection,
3161 	natural_t notification_type,
3162 	semaphore_t *semaphore )
3163 {
3164 	IOReturn ret;
3165 	CHECK( IOUserClient, connection, client );
3166 
3167 	IOStatisticsClientCall();
3168 	IORWLockWrite(client->lock);
3169 	ret = client->getNotificationSemaphore((UInt32) notification_type,
3170 	    semaphore );
3171 	IORWLockUnlock(client->lock);
3172 
3173 	return ret;
3174 }
3175 
3176 /* Routine io_registry_get_root_entry */
3177 kern_return_t
is_io_registry_get_root_entry(mach_port_t master_port,io_object_t * root)3178 is_io_registry_get_root_entry(
3179 	mach_port_t master_port,
3180 	io_object_t *root )
3181 {
3182 	IORegistryEntry *   entry;
3183 
3184 	if (master_port != master_device_port) {
3185 		return kIOReturnNotPrivileged;
3186 	}
3187 
3188 	entry = IORegistryEntry::getRegistryRoot();
3189 	if (entry) {
3190 		entry->retain();
3191 	}
3192 	*root = entry;
3193 
3194 	return kIOReturnSuccess;
3195 }
3196 
3197 /* Routine io_registry_create_iterator */
3198 kern_return_t
is_io_registry_create_iterator(mach_port_t master_port,io_name_t plane,uint32_t options,io_object_t * iterator)3199 is_io_registry_create_iterator(
3200 	mach_port_t master_port,
3201 	io_name_t plane,
3202 	uint32_t options,
3203 	io_object_t *iterator )
3204 {
3205 	if (master_port != master_device_port) {
3206 		return kIOReturnNotPrivileged;
3207 	}
3208 
3209 	*iterator = IOUserIterator::withIterator(
3210 		IORegistryIterator::iterateOver(
3211 			IORegistryEntry::getPlane( plane ), options ));
3212 
3213 	return *iterator ? kIOReturnSuccess : kIOReturnBadArgument;
3214 }
3215 
3216 /* Routine io_registry_entry_create_iterator */
3217 kern_return_t
is_io_registry_entry_create_iterator(io_object_t registry_entry,io_name_t plane,uint32_t options,io_object_t * iterator)3218 is_io_registry_entry_create_iterator(
3219 	io_object_t registry_entry,
3220 	io_name_t plane,
3221 	uint32_t options,
3222 	io_object_t *iterator )
3223 {
3224 	CHECK( IORegistryEntry, registry_entry, entry );
3225 
3226 	*iterator = IOUserIterator::withIterator(
3227 		IORegistryIterator::iterateOver( entry,
3228 		IORegistryEntry::getPlane( plane ), options ));
3229 
3230 	return *iterator ? kIOReturnSuccess : kIOReturnBadArgument;
3231 }
3232 
3233 /* Routine io_registry_iterator_enter */
3234 kern_return_t
is_io_registry_iterator_enter_entry(io_object_t iterator)3235 is_io_registry_iterator_enter_entry(
3236 	io_object_t iterator )
3237 {
3238 	CHECKLOCKED( IORegistryIterator, iterator, iter );
3239 
3240 	IOLockLock(oIter->lock);
3241 	iter->enterEntry();
3242 	IOLockUnlock(oIter->lock);
3243 
3244 	return kIOReturnSuccess;
3245 }
3246 
3247 /* Routine io_registry_iterator_exit */
3248 kern_return_t
is_io_registry_iterator_exit_entry(io_object_t iterator)3249 is_io_registry_iterator_exit_entry(
3250 	io_object_t iterator )
3251 {
3252 	bool        didIt;
3253 
3254 	CHECKLOCKED( IORegistryIterator, iterator, iter );
3255 
3256 	IOLockLock(oIter->lock);
3257 	didIt = iter->exitEntry();
3258 	IOLockUnlock(oIter->lock);
3259 
3260 	return didIt ? kIOReturnSuccess : kIOReturnNoDevice;
3261 }
3262 
3263 /* Routine io_registry_entry_from_path */
3264 kern_return_t
is_io_registry_entry_from_path(mach_port_t master_port,io_string_t path,io_object_t * registry_entry)3265 is_io_registry_entry_from_path(
3266 	mach_port_t master_port,
3267 	io_string_t path,
3268 	io_object_t *registry_entry )
3269 {
3270 	IORegistryEntry *   entry;
3271 
3272 	if (master_port != master_device_port) {
3273 		return kIOReturnNotPrivileged;
3274 	}
3275 
3276 	entry = IORegistryEntry::fromPath( path );
3277 
3278 	if (!entry && IOTaskRegistryCompatibility(current_task())) {
3279 		OSDictionary * matching;
3280 		const OSObject * objects[2] = { kOSBooleanTrue, NULL };
3281 		const OSSymbol * keys[2]    = { gIOCompatibilityMatchKey, gIOPathMatchKey };
3282 
3283 		objects[1] = OSString::withCStringNoCopy(path);
3284 		matching = OSDictionary::withObjects(objects, keys, 2, 2);
3285 		if (matching) {
3286 			entry = IOService::copyMatchingService(matching);
3287 		}
3288 		OSSafeReleaseNULL(matching);
3289 		OSSafeReleaseNULL(objects[1]);
3290 	}
3291 
3292 	*registry_entry = entry;
3293 
3294 	return kIOReturnSuccess;
3295 }
3296 
3297 
3298 /* Routine io_registry_entry_from_path */
3299 kern_return_t
is_io_registry_entry_from_path_ool(mach_port_t master_port,io_string_inband_t path,io_buf_ptr_t path_ool,mach_msg_type_number_t path_oolCnt,kern_return_t * result,io_object_t * registry_entry)3300 is_io_registry_entry_from_path_ool(
3301 	mach_port_t master_port,
3302 	io_string_inband_t path,
3303 	io_buf_ptr_t path_ool,
3304 	mach_msg_type_number_t path_oolCnt,
3305 	kern_return_t *result,
3306 	io_object_t *registry_entry)
3307 {
3308 	IORegistryEntry *   entry;
3309 	vm_map_offset_t     map_data;
3310 	const char *        cpath;
3311 	IOReturn            res;
3312 	kern_return_t       err;
3313 
3314 	if (master_port != master_device_port) {
3315 		return kIOReturnNotPrivileged;
3316 	}
3317 
3318 	map_data = 0;
3319 	entry    = NULL;
3320 	res = err = KERN_SUCCESS;
3321 	if (path[0]) {
3322 		cpath = path;
3323 	} else {
3324 		if (!path_oolCnt) {
3325 			return kIOReturnBadArgument;
3326 		}
3327 		if (path_oolCnt > (sizeof(io_struct_inband_t) * 1024)) {
3328 			return kIOReturnMessageTooLarge;
3329 		}
3330 
3331 		err = vm_map_copyout(kernel_map, &map_data, (vm_map_copy_t) path_ool);
3332 		if (KERN_SUCCESS == err) {
3333 			// must return success to mig after vm_map_copyout() succeeds, so result is actual
3334 			cpath = CAST_DOWN(const char *, map_data);
3335 			if (cpath[path_oolCnt - 1]) {
3336 				res = kIOReturnBadArgument;
3337 			}
3338 		}
3339 	}
3340 
3341 	if ((KERN_SUCCESS == err) && (KERN_SUCCESS == res)) {
3342 		entry = IORegistryEntry::fromPath(cpath);
3343 		res = entry ? kIOReturnSuccess : kIOReturnNotFound;
3344 	}
3345 
3346 	if (map_data) {
3347 		vm_deallocate(kernel_map, map_data, path_oolCnt);
3348 	}
3349 
3350 	if (KERN_SUCCESS != err) {
3351 		res = err;
3352 	}
3353 	*registry_entry = entry;
3354 	*result = res;
3355 
3356 	return err;
3357 }
3358 
3359 
3360 /* Routine io_registry_entry_in_plane */
3361 kern_return_t
is_io_registry_entry_in_plane(io_object_t registry_entry,io_name_t plane,boolean_t * inPlane)3362 is_io_registry_entry_in_plane(
3363 	io_object_t registry_entry,
3364 	io_name_t plane,
3365 	boolean_t *inPlane )
3366 {
3367 	CHECK( IORegistryEntry, registry_entry, entry );
3368 
3369 	*inPlane = entry->inPlane( IORegistryEntry::getPlane( plane ));
3370 
3371 	return kIOReturnSuccess;
3372 }
3373 
3374 
3375 /* Routine io_registry_entry_get_path */
3376 kern_return_t
is_io_registry_entry_get_path(io_object_t registry_entry,io_name_t plane,io_string_t path)3377 is_io_registry_entry_get_path(
3378 	io_object_t registry_entry,
3379 	io_name_t plane,
3380 	io_string_t path )
3381 {
3382 	int         length;
3383 	CHECK( IORegistryEntry, registry_entry, entry );
3384 
3385 	length = sizeof(io_string_t);
3386 	if (entry->getPath( path, &length, IORegistryEntry::getPlane( plane ))) {
3387 		return kIOReturnSuccess;
3388 	} else {
3389 		return kIOReturnBadArgument;
3390 	}
3391 }
3392 
3393 /* Routine io_registry_entry_get_path */
3394 kern_return_t
is_io_registry_entry_get_path_ool(io_object_t registry_entry,io_name_t plane,io_string_inband_t path,io_buf_ptr_t * path_ool,mach_msg_type_number_t * path_oolCnt)3395 is_io_registry_entry_get_path_ool(
3396 	io_object_t registry_entry,
3397 	io_name_t plane,
3398 	io_string_inband_t path,
3399 	io_buf_ptr_t *path_ool,
3400 	mach_msg_type_number_t *path_oolCnt)
3401 {
3402 	enum   { kMaxPath = 16384 };
3403 	IOReturn err;
3404 	int      length;
3405 	char   * buf;
3406 
3407 	CHECK( IORegistryEntry, registry_entry, entry );
3408 
3409 	*path_ool    = NULL;
3410 	*path_oolCnt = 0;
3411 	length = sizeof(io_string_inband_t);
3412 	if (entry->getPath(path, &length, IORegistryEntry::getPlane(plane))) {
3413 		err = kIOReturnSuccess;
3414 	} else {
3415 		length = kMaxPath;
3416 		buf = IONewData(char, length);
3417 		if (!buf) {
3418 			err = kIOReturnNoMemory;
3419 		} else if (!entry->getPath(buf, &length, IORegistryEntry::getPlane(plane))) {
3420 			err = kIOReturnError;
3421 		} else {
3422 			*path_oolCnt = length;
3423 			err = copyoutkdata(buf, length, path_ool);
3424 		}
3425 		if (buf) {
3426 			IODeleteData(buf, char, kMaxPath);
3427 		}
3428 	}
3429 
3430 	return err;
3431 }
3432 
3433 
3434 /* Routine io_registry_entry_get_name */
3435 kern_return_t
is_io_registry_entry_get_name(io_object_t registry_entry,io_name_t name)3436 is_io_registry_entry_get_name(
3437 	io_object_t registry_entry,
3438 	io_name_t name )
3439 {
3440 	CHECK( IORegistryEntry, registry_entry, entry );
3441 
3442 	strncpy( name, entry->getName(), sizeof(io_name_t));
3443 
3444 	return kIOReturnSuccess;
3445 }
3446 
3447 /* Routine io_registry_entry_get_name_in_plane */
3448 kern_return_t
is_io_registry_entry_get_name_in_plane(io_object_t registry_entry,io_name_t planeName,io_name_t name)3449 is_io_registry_entry_get_name_in_plane(
3450 	io_object_t registry_entry,
3451 	io_name_t planeName,
3452 	io_name_t name )
3453 {
3454 	const IORegistryPlane * plane;
3455 	CHECK( IORegistryEntry, registry_entry, entry );
3456 
3457 	if (planeName[0]) {
3458 		plane = IORegistryEntry::getPlane( planeName );
3459 	} else {
3460 		plane = NULL;
3461 	}
3462 
3463 	strncpy( name, entry->getName( plane), sizeof(io_name_t));
3464 
3465 	return kIOReturnSuccess;
3466 }
3467 
3468 /* Routine io_registry_entry_get_location_in_plane */
3469 kern_return_t
is_io_registry_entry_get_location_in_plane(io_object_t registry_entry,io_name_t planeName,io_name_t location)3470 is_io_registry_entry_get_location_in_plane(
3471 	io_object_t registry_entry,
3472 	io_name_t planeName,
3473 	io_name_t location )
3474 {
3475 	const IORegistryPlane * plane;
3476 	CHECK( IORegistryEntry, registry_entry, entry );
3477 
3478 	if (planeName[0]) {
3479 		plane = IORegistryEntry::getPlane( planeName );
3480 	} else {
3481 		plane = NULL;
3482 	}
3483 
3484 	const char * cstr = entry->getLocation( plane );
3485 
3486 	if (cstr) {
3487 		strncpy( location, cstr, sizeof(io_name_t));
3488 		return kIOReturnSuccess;
3489 	} else {
3490 		return kIOReturnNotFound;
3491 	}
3492 }
3493 
3494 /* Routine io_registry_entry_get_registry_entry_id */
3495 kern_return_t
is_io_registry_entry_get_registry_entry_id(io_object_t registry_entry,uint64_t * entry_id)3496 is_io_registry_entry_get_registry_entry_id(
3497 	io_object_t registry_entry,
3498 	uint64_t *entry_id )
3499 {
3500 	CHECK( IORegistryEntry, registry_entry, entry );
3501 
3502 	*entry_id = entry->getRegistryEntryID();
3503 
3504 	return kIOReturnSuccess;
3505 }
3506 
3507 
3508 static OSObject *
IOCopyPropertyCompatible(IORegistryEntry * regEntry,const char * name)3509 IOCopyPropertyCompatible(IORegistryEntry * regEntry, const char * name)
3510 {
3511 	OSObject     * obj;
3512 	OSObject     * compatProperties;
3513 	OSDictionary * props;
3514 
3515 	obj = regEntry->copyProperty(name);
3516 	if (obj) {
3517 		return obj;
3518 	}
3519 
3520 	compatProperties = regEntry->copyProperty(gIOUserServicePropertiesKey);
3521 	if (!compatProperties
3522 	    && IOTaskRegistryCompatibility(current_task())) {
3523 		compatProperties = regEntry->copyProperty(gIOCompatibilityPropertiesKey);
3524 	}
3525 	if (compatProperties) {
3526 		props = OSDynamicCast(OSDictionary, compatProperties);
3527 		if (props) {
3528 			obj = props->getObject(name);
3529 			if (obj) {
3530 				obj->retain();
3531 			}
3532 		}
3533 		compatProperties->release();
3534 	}
3535 
3536 	return obj;
3537 }
3538 
3539 /* Routine io_registry_entry_get_property */
3540 kern_return_t
is_io_registry_entry_get_property_bytes(io_object_t registry_entry,io_name_t property_name,io_struct_inband_t buf,mach_msg_type_number_t * dataCnt)3541 is_io_registry_entry_get_property_bytes(
3542 	io_object_t registry_entry,
3543 	io_name_t property_name,
3544 	io_struct_inband_t buf,
3545 	mach_msg_type_number_t *dataCnt )
3546 {
3547 	OSObject    *       obj;
3548 	OSData      *       data;
3549 	OSString    *       str;
3550 	OSBoolean   *       boo;
3551 	OSNumber    *       off;
3552 	UInt64              offsetBytes;
3553 	unsigned int        len = 0;
3554 	const void *        bytes = NULL;
3555 	IOReturn            ret = kIOReturnSuccess;
3556 
3557 	CHECK( IORegistryEntry, registry_entry, entry );
3558 
3559 #if CONFIG_MACF
3560 	if (0 != mac_iokit_check_get_property(kauth_cred_get(), entry, property_name)) {
3561 		return kIOReturnNotPermitted;
3562 	}
3563 #endif
3564 
3565 	obj = IOCopyPropertyCompatible(entry, property_name);
3566 	if (!obj) {
3567 		return kIOReturnNoResources;
3568 	}
3569 
3570 	// One day OSData will be a common container base class
3571 	// until then...
3572 	if ((data = OSDynamicCast( OSData, obj ))) {
3573 		len = data->getLength();
3574 		bytes = data->getBytesNoCopy();
3575 		if (!data->isSerializable()) {
3576 			len = 0;
3577 		}
3578 	} else if ((str = OSDynamicCast( OSString, obj ))) {
3579 		len = str->getLength() + 1;
3580 		bytes = str->getCStringNoCopy();
3581 	} else if ((boo = OSDynamicCast( OSBoolean, obj ))) {
3582 		len = boo->isTrue() ? sizeof("Yes") : sizeof("No");
3583 		bytes = boo->isTrue() ? "Yes" : "No";
3584 	} else if ((off = OSDynamicCast( OSNumber, obj ))) {
3585 		offsetBytes = off->unsigned64BitValue();
3586 		len = off->numberOfBytes();
3587 		if (len > sizeof(offsetBytes)) {
3588 			len = sizeof(offsetBytes);
3589 		}
3590 		bytes = &offsetBytes;
3591 #ifdef __BIG_ENDIAN__
3592 		bytes = (const void *)
3593 		    (((UInt32) bytes) + (sizeof(UInt64) - len));
3594 #endif
3595 	} else {
3596 		ret = kIOReturnBadArgument;
3597 	}
3598 
3599 	if (bytes) {
3600 		if (*dataCnt < len) {
3601 			ret = kIOReturnIPCError;
3602 		} else {
3603 			*dataCnt = len;
3604 			bcopy( bytes, buf, len );
3605 		}
3606 	}
3607 	obj->release();
3608 
3609 	return ret;
3610 }
3611 
3612 
3613 /* Routine io_registry_entry_get_property */
3614 kern_return_t
is_io_registry_entry_get_property(io_object_t registry_entry,io_name_t property_name,io_buf_ptr_t * properties,mach_msg_type_number_t * propertiesCnt)3615 is_io_registry_entry_get_property(
3616 	io_object_t registry_entry,
3617 	io_name_t property_name,
3618 	io_buf_ptr_t *properties,
3619 	mach_msg_type_number_t *propertiesCnt )
3620 {
3621 	kern_return_t       err;
3622 	unsigned int        len;
3623 	OSObject *          obj;
3624 
3625 	CHECK( IORegistryEntry, registry_entry, entry );
3626 
3627 #if CONFIG_MACF
3628 	if (0 != mac_iokit_check_get_property(kauth_cred_get(), entry, property_name)) {
3629 		return kIOReturnNotPermitted;
3630 	}
3631 #endif
3632 
3633 	obj = IOCopyPropertyCompatible(entry, property_name);
3634 	if (!obj) {
3635 		return kIOReturnNotFound;
3636 	}
3637 
3638 	OSSerialize * s = OSSerialize::withCapacity(4096);
3639 	if (!s) {
3640 		obj->release();
3641 		return kIOReturnNoMemory;
3642 	}
3643 
3644 	if (obj->serialize( s )) {
3645 		len = s->getLength();
3646 		*propertiesCnt = len;
3647 		err = copyoutkdata( s->text(), len, properties );
3648 	} else {
3649 		err = kIOReturnUnsupported;
3650 	}
3651 
3652 	s->release();
3653 	obj->release();
3654 
3655 	return err;
3656 }
3657 
3658 /* Routine io_registry_entry_get_property_recursively */
3659 kern_return_t
is_io_registry_entry_get_property_recursively(io_object_t registry_entry,io_name_t plane,io_name_t property_name,uint32_t options,io_buf_ptr_t * properties,mach_msg_type_number_t * propertiesCnt)3660 is_io_registry_entry_get_property_recursively(
3661 	io_object_t registry_entry,
3662 	io_name_t plane,
3663 	io_name_t property_name,
3664 	uint32_t options,
3665 	io_buf_ptr_t *properties,
3666 	mach_msg_type_number_t *propertiesCnt )
3667 {
3668 	kern_return_t       err;
3669 	unsigned int        len;
3670 	OSObject *          obj;
3671 
3672 	CHECK( IORegistryEntry, registry_entry, entry );
3673 
3674 #if CONFIG_MACF
3675 	if (0 != mac_iokit_check_get_property(kauth_cred_get(), entry, property_name)) {
3676 		return kIOReturnNotPermitted;
3677 	}
3678 #endif
3679 
3680 	obj = entry->copyProperty( property_name,
3681 	    IORegistryEntry::getPlane( plane ), options );
3682 	if (!obj) {
3683 		return kIOReturnNotFound;
3684 	}
3685 
3686 	OSSerialize * s = OSSerialize::withCapacity(4096);
3687 	if (!s) {
3688 		obj->release();
3689 		return kIOReturnNoMemory;
3690 	}
3691 
3692 	if (obj->serialize( s )) {
3693 		len = s->getLength();
3694 		*propertiesCnt = len;
3695 		err = copyoutkdata( s->text(), len, properties );
3696 	} else {
3697 		err = kIOReturnUnsupported;
3698 	}
3699 
3700 	s->release();
3701 	obj->release();
3702 
3703 	return err;
3704 }
3705 
3706 /* Routine io_registry_entry_get_properties */
3707 kern_return_t
is_io_registry_entry_get_properties(io_object_t registry_entry,io_buf_ptr_t * properties,mach_msg_type_number_t * propertiesCnt)3708 is_io_registry_entry_get_properties(
3709 	io_object_t registry_entry,
3710 	io_buf_ptr_t *properties,
3711 	mach_msg_type_number_t *propertiesCnt )
3712 {
3713 	return kIOReturnUnsupported;
3714 }
3715 
3716 #if CONFIG_MACF
3717 
3718 struct GetPropertiesEditorRef {
3719 	kauth_cred_t      cred;
3720 	IORegistryEntry * entry;
3721 	OSCollection    * root;
3722 };
3723 
3724 static const LIBKERN_RETURNS_RETAINED OSMetaClassBase *
GetPropertiesEditor(void * reference,OSSerialize * s,OSCollection * container,const OSSymbol * name,const OSMetaClassBase * value)3725 GetPropertiesEditor(void                  * reference,
3726     OSSerialize           * s,
3727     OSCollection          * container,
3728     const OSSymbol        * name,
3729     const OSMetaClassBase * value)
3730 {
3731 	GetPropertiesEditorRef * ref = (typeof(ref))reference;
3732 
3733 	if (!ref->root) {
3734 		ref->root = container;
3735 	}
3736 	if (ref->root == container) {
3737 		if (0 != mac_iokit_check_get_property(ref->cred, ref->entry, name->getCStringNoCopy())) {
3738 			value = NULL;
3739 		}
3740 	}
3741 	if (value) {
3742 		value->retain();
3743 	}
3744 	return value;
3745 }
3746 
3747 #endif /* CONFIG_MACF */
3748 
3749 /* Routine io_registry_entry_get_properties_bin_buf */
3750 kern_return_t
is_io_registry_entry_get_properties_bin_buf(io_object_t registry_entry,mach_vm_address_t buf,mach_vm_size_t * bufsize,io_buf_ptr_t * properties,mach_msg_type_number_t * propertiesCnt)3751 is_io_registry_entry_get_properties_bin_buf(
3752 	io_object_t registry_entry,
3753 	mach_vm_address_t buf,
3754 	mach_vm_size_t *bufsize,
3755 	io_buf_ptr_t *properties,
3756 	mach_msg_type_number_t *propertiesCnt)
3757 {
3758 	kern_return_t          err = kIOReturnSuccess;
3759 	unsigned int           len;
3760 	OSObject             * compatProperties;
3761 	OSSerialize          * s;
3762 	OSSerialize::Editor    editor = NULL;
3763 	void                 * editRef = NULL;
3764 
3765 	CHECK(IORegistryEntry, registry_entry, entry);
3766 
3767 #if CONFIG_MACF
3768 	GetPropertiesEditorRef ref;
3769 	if (mac_iokit_check_filter_properties(kauth_cred_get(), entry)) {
3770 		editor    = &GetPropertiesEditor;
3771 		editRef   = &ref;
3772 		ref.cred  = kauth_cred_get();
3773 		ref.entry = entry;
3774 		ref.root  = NULL;
3775 	}
3776 #endif
3777 
3778 	s = OSSerialize::binaryWithCapacity(4096, editor, editRef);
3779 	if (!s) {
3780 		return kIOReturnNoMemory;
3781 	}
3782 
3783 
3784 	compatProperties = entry->copyProperty(gIOUserServicePropertiesKey);
3785 	if (!compatProperties
3786 	    && IOTaskRegistryCompatibility(current_task())) {
3787 		compatProperties = entry->copyProperty(gIOCompatibilityPropertiesKey);
3788 	}
3789 
3790 	if (compatProperties) {
3791 		OSDictionary * dict;
3792 
3793 		dict = entry->dictionaryWithProperties();
3794 		if (!dict) {
3795 			err = kIOReturnNoMemory;
3796 		} else {
3797 			dict->removeObject(gIOUserServicePropertiesKey);
3798 			dict->removeObject(gIOCompatibilityPropertiesKey);
3799 			dict->merge(OSDynamicCast(OSDictionary, compatProperties));
3800 			if (!dict->serialize(s)) {
3801 				err = kIOReturnUnsupported;
3802 			}
3803 			dict->release();
3804 		}
3805 		compatProperties->release();
3806 	} else if (!entry->serializeProperties(s)) {
3807 		err = kIOReturnUnsupported;
3808 	}
3809 
3810 	if (kIOReturnSuccess == err) {
3811 		len = s->getLength();
3812 		if (buf && bufsize && len <= *bufsize) {
3813 			*bufsize = len;
3814 			*propertiesCnt = 0;
3815 			*properties = nullptr;
3816 			if (copyout(s->text(), buf, len)) {
3817 				err = kIOReturnVMError;
3818 			} else {
3819 				err = kIOReturnSuccess;
3820 			}
3821 		} else {
3822 			if (bufsize) {
3823 				*bufsize = 0;
3824 			}
3825 			*propertiesCnt = len;
3826 			err = copyoutkdata( s->text(), len, properties );
3827 		}
3828 	}
3829 	s->release();
3830 
3831 	return err;
3832 }
3833 
3834 /* Routine io_registry_entry_get_properties_bin */
3835 kern_return_t
is_io_registry_entry_get_properties_bin(io_object_t registry_entry,io_buf_ptr_t * properties,mach_msg_type_number_t * propertiesCnt)3836 is_io_registry_entry_get_properties_bin(
3837 	io_object_t registry_entry,
3838 	io_buf_ptr_t *properties,
3839 	mach_msg_type_number_t *propertiesCnt)
3840 {
3841 	return is_io_registry_entry_get_properties_bin_buf(registry_entry,
3842 	           0, NULL, properties, propertiesCnt);
3843 }
3844 
3845 /* Routine io_registry_entry_get_property_bin_buf */
3846 kern_return_t
is_io_registry_entry_get_property_bin_buf(io_object_t registry_entry,io_name_t plane,io_name_t property_name,uint32_t options,mach_vm_address_t buf,mach_vm_size_t * bufsize,io_buf_ptr_t * properties,mach_msg_type_number_t * propertiesCnt)3847 is_io_registry_entry_get_property_bin_buf(
3848 	io_object_t registry_entry,
3849 	io_name_t plane,
3850 	io_name_t property_name,
3851 	uint32_t options,
3852 	mach_vm_address_t buf,
3853 	mach_vm_size_t *bufsize,
3854 	io_buf_ptr_t *properties,
3855 	mach_msg_type_number_t *propertiesCnt )
3856 {
3857 	kern_return_t       err;
3858 	unsigned int        len;
3859 	OSObject *          obj;
3860 	const OSSymbol *    sym;
3861 
3862 	CHECK( IORegistryEntry, registry_entry, entry );
3863 
3864 #if CONFIG_MACF
3865 	if (0 != mac_iokit_check_get_property(kauth_cred_get(), entry, property_name)) {
3866 		return kIOReturnNotPermitted;
3867 	}
3868 #endif
3869 
3870 	sym = OSSymbol::withCString(property_name);
3871 	if (!sym) {
3872 		return kIOReturnNoMemory;
3873 	}
3874 
3875 	err = kIOReturnNotFound;
3876 	if (gIORegistryEntryPropertyKeysKey == sym) {
3877 		obj = entry->copyPropertyKeys();
3878 	} else {
3879 		if ((kIORegistryIterateRecursively & options) && plane[0]) {
3880 			obj = IOCopyPropertyCompatible(entry, property_name);
3881 			if (obj == NULL) {
3882 				IORegistryIterator * iter = IORegistryIterator::iterateOver(entry, IORegistryEntry::getPlane(plane), options);
3883 				if (iter) {
3884 					while ((NULL == obj) && (entry = iter->getNextObject())) {
3885 						OSObject * currentObj = IOCopyPropertyCompatible(entry, property_name);
3886 #if CONFIG_MACF
3887 						if (currentObj != NULL && 0 != mac_iokit_check_get_property(kauth_cred_get(), entry, property_name)) {
3888 							// Record that MAC hook blocked this entry and property, and continue to next entry
3889 							err = kIOReturnNotPermitted;
3890 							OSSafeReleaseNULL(currentObj);
3891 							continue;
3892 						}
3893 #endif
3894 						obj = currentObj;
3895 					}
3896 					iter->release();
3897 				}
3898 			}
3899 		} else {
3900 			obj = IOCopyPropertyCompatible(entry, property_name);
3901 		}
3902 		if (obj && gIORemoveOnReadProperties->containsObject(sym)) {
3903 			entry->removeProperty(sym);
3904 		}
3905 	}
3906 
3907 	sym->release();
3908 	if (!obj) {
3909 		return err;
3910 	}
3911 
3912 	OSSerialize * s = OSSerialize::binaryWithCapacity(4096);
3913 	if (!s) {
3914 		obj->release();
3915 		return kIOReturnNoMemory;
3916 	}
3917 
3918 	if (obj->serialize( s )) {
3919 		len = s->getLength();
3920 		if (buf && bufsize && len <= *bufsize) {
3921 			*bufsize = len;
3922 			*propertiesCnt = 0;
3923 			*properties = nullptr;
3924 			if (copyout(s->text(), buf, len)) {
3925 				err = kIOReturnVMError;
3926 			} else {
3927 				err = kIOReturnSuccess;
3928 			}
3929 		} else {
3930 			if (bufsize) {
3931 				*bufsize = 0;
3932 			}
3933 			*propertiesCnt = len;
3934 			err = copyoutkdata( s->text(), len, properties );
3935 		}
3936 	} else {
3937 		err = kIOReturnUnsupported;
3938 	}
3939 
3940 	s->release();
3941 	obj->release();
3942 
3943 	return err;
3944 }
3945 
3946 /* Routine io_registry_entry_get_property_bin */
3947 kern_return_t
is_io_registry_entry_get_property_bin(io_object_t registry_entry,io_name_t plane,io_name_t property_name,uint32_t options,io_buf_ptr_t * properties,mach_msg_type_number_t * propertiesCnt)3948 is_io_registry_entry_get_property_bin(
3949 	io_object_t registry_entry,
3950 	io_name_t plane,
3951 	io_name_t property_name,
3952 	uint32_t options,
3953 	io_buf_ptr_t *properties,
3954 	mach_msg_type_number_t *propertiesCnt )
3955 {
3956 	return is_io_registry_entry_get_property_bin_buf(registry_entry, plane,
3957 	           property_name, options, 0, NULL, properties, propertiesCnt);
3958 }
3959 
3960 
3961 /* Routine io_registry_entry_set_properties */
3962 kern_return_t
is_io_registry_entry_set_properties(io_object_t registry_entry,io_buf_ptr_t properties,mach_msg_type_number_t propertiesCnt,kern_return_t * result)3963 is_io_registry_entry_set_properties
3964 (
3965 	io_object_t registry_entry,
3966 	io_buf_ptr_t properties,
3967 	mach_msg_type_number_t propertiesCnt,
3968 	kern_return_t * result)
3969 {
3970 	OSObject *          obj;
3971 	kern_return_t       err;
3972 	IOReturn            res;
3973 	vm_offset_t         data;
3974 	vm_map_offset_t     map_data;
3975 
3976 	CHECK( IORegistryEntry, registry_entry, entry );
3977 
3978 	if (propertiesCnt > sizeof(io_struct_inband_t) * 1024) {
3979 		return kIOReturnMessageTooLarge;
3980 	}
3981 
3982 	err = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) properties );
3983 	data = CAST_DOWN(vm_offset_t, map_data);
3984 
3985 	if (KERN_SUCCESS == err) {
3986 		FAKE_STACK_FRAME(entry->getMetaClass());
3987 
3988 		// must return success after vm_map_copyout() succeeds
3989 		obj = OSUnserializeXML((const char *) data, propertiesCnt );
3990 		vm_deallocate( kernel_map, data, propertiesCnt );
3991 
3992 		if (!obj) {
3993 			res = kIOReturnBadArgument;
3994 		}
3995 #if CONFIG_MACF
3996 		else if (0 != mac_iokit_check_set_properties(kauth_cred_get(),
3997 		    registry_entry, obj)) {
3998 			res = kIOReturnNotPermitted;
3999 		}
4000 #endif
4001 		else {
4002 			res = entry->setProperties( obj );
4003 			IOService * service = OSDynamicCast(IOService, entry);
4004 			OSDictionary * props = OSDynamicCast(OSDictionary, obj);
4005 			if (service && props && service->hasUserServer()) {
4006 				res = service->UserSetProperties(props);
4007 			}
4008 		}
4009 
4010 		if (obj) {
4011 			obj->release();
4012 		}
4013 
4014 		FAKE_STACK_FRAME_END();
4015 	} else {
4016 		res = err;
4017 	}
4018 
4019 	*result = res;
4020 	return err;
4021 }
4022 
4023 /* Routine io_registry_entry_get_child_iterator */
4024 kern_return_t
is_io_registry_entry_get_child_iterator(io_object_t registry_entry,io_name_t plane,io_object_t * iterator)4025 is_io_registry_entry_get_child_iterator(
4026 	io_object_t registry_entry,
4027 	io_name_t plane,
4028 	io_object_t *iterator )
4029 {
4030 	CHECK( IORegistryEntry, registry_entry, entry );
4031 
4032 	*iterator = IOUserIterator::withIterator(entry->getChildIterator(
4033 		    IORegistryEntry::getPlane( plane )));
4034 
4035 	return kIOReturnSuccess;
4036 }
4037 
4038 /* Routine io_registry_entry_get_parent_iterator */
4039 kern_return_t
is_io_registry_entry_get_parent_iterator(io_object_t registry_entry,io_name_t plane,io_object_t * iterator)4040 is_io_registry_entry_get_parent_iterator(
4041 	io_object_t registry_entry,
4042 	io_name_t plane,
4043 	io_object_t *iterator)
4044 {
4045 	CHECK( IORegistryEntry, registry_entry, entry );
4046 
4047 	*iterator = IOUserIterator::withIterator(entry->getParentIterator(
4048 		    IORegistryEntry::getPlane( plane )));
4049 
4050 	return kIOReturnSuccess;
4051 }
4052 
4053 /* Routine io_service_get_busy_state */
4054 kern_return_t
is_io_service_get_busy_state(io_object_t _service,uint32_t * busyState)4055 is_io_service_get_busy_state(
4056 	io_object_t _service,
4057 	uint32_t *busyState )
4058 {
4059 	CHECK( IOService, _service, service );
4060 
4061 	*busyState = service->getBusyState();
4062 
4063 	return kIOReturnSuccess;
4064 }
4065 
4066 /* Routine io_service_get_state */
4067 kern_return_t
is_io_service_get_state(io_object_t _service,uint64_t * state,uint32_t * busy_state,uint64_t * accumulated_busy_time)4068 is_io_service_get_state(
4069 	io_object_t _service,
4070 	uint64_t *state,
4071 	uint32_t *busy_state,
4072 	uint64_t *accumulated_busy_time )
4073 {
4074 	CHECK( IOService, _service, service );
4075 
4076 	*state                 = service->getState();
4077 	*busy_state            = service->getBusyState();
4078 	*accumulated_busy_time = service->getAccumulatedBusyTime();
4079 
4080 	return kIOReturnSuccess;
4081 }
4082 
4083 /* Routine io_service_wait_quiet */
4084 kern_return_t
is_io_service_wait_quiet(io_object_t _service,mach_timespec_t wait_time)4085 is_io_service_wait_quiet(
4086 	io_object_t _service,
4087 	mach_timespec_t wait_time )
4088 {
4089 	uint64_t    timeoutNS;
4090 
4091 	CHECK( IOService, _service, service );
4092 
4093 	timeoutNS = wait_time.tv_sec;
4094 	timeoutNS *= kSecondScale;
4095 	timeoutNS += wait_time.tv_nsec;
4096 
4097 	return service->waitQuiet(timeoutNS);
4098 }
4099 
4100 /* Routine io_service_request_probe */
4101 kern_return_t
is_io_service_request_probe(io_object_t _service,uint32_t options)4102 is_io_service_request_probe(
4103 	io_object_t _service,
4104 	uint32_t options )
4105 {
4106 	CHECK( IOService, _service, service );
4107 
4108 	return service->requestProbe( options );
4109 }
4110 
4111 /* Routine io_service_get_authorization_id */
4112 kern_return_t
is_io_service_get_authorization_id(io_object_t _service,uint64_t * authorization_id)4113 is_io_service_get_authorization_id(
4114 	io_object_t _service,
4115 	uint64_t *authorization_id )
4116 {
4117 	kern_return_t          kr;
4118 
4119 	CHECK( IOService, _service, service );
4120 
4121 	kr = IOUserClient::clientHasPrivilege((void *) current_task(),
4122 	    kIOClientPrivilegeAdministrator );
4123 	if (kIOReturnSuccess != kr) {
4124 		return kr;
4125 	}
4126 
4127 	*authorization_id = service->getAuthorizationID();
4128 
4129 	return kr;
4130 }
4131 
4132 /* Routine io_service_set_authorization_id */
4133 kern_return_t
is_io_service_set_authorization_id(io_object_t _service,uint64_t authorization_id)4134 is_io_service_set_authorization_id(
4135 	io_object_t _service,
4136 	uint64_t authorization_id )
4137 {
4138 	CHECK( IOService, _service, service );
4139 
4140 	return service->setAuthorizationID( authorization_id );
4141 }
4142 
4143 /* Routine io_service_open_ndr */
4144 kern_return_t
is_io_service_open_extended(io_object_t _service,task_t owningTask,uint32_t connect_type,NDR_record_t ndr,io_buf_ptr_t properties,mach_msg_type_number_t propertiesCnt,kern_return_t * result,io_object_t * connection)4145 is_io_service_open_extended(
4146 	io_object_t _service,
4147 	task_t owningTask,
4148 	uint32_t connect_type,
4149 	NDR_record_t ndr,
4150 	io_buf_ptr_t properties,
4151 	mach_msg_type_number_t propertiesCnt,
4152 	kern_return_t * result,
4153 	io_object_t *connection )
4154 {
4155 	IOUserClient * client = NULL;
4156 	kern_return_t  err = KERN_SUCCESS;
4157 	IOReturn       res = kIOReturnSuccess;
4158 	OSDictionary * propertiesDict = NULL;
4159 	bool           crossEndian;
4160 	bool           disallowAccess;
4161 
4162 	CHECK( IOService, _service, service );
4163 
4164 	if (!owningTask) {
4165 		return kIOReturnBadArgument;
4166 	}
4167 	assert(owningTask == current_task());
4168 	if (owningTask != current_task()) {
4169 		return kIOReturnBadArgument;
4170 	}
4171 
4172 #if CONFIG_MACF
4173 	if (mac_iokit_check_open_service(kauth_cred_get(), service, connect_type) != 0) {
4174 		return kIOReturnNotPermitted;
4175 	}
4176 #endif
4177 	do{
4178 		if (properties) {
4179 			return kIOReturnUnsupported;
4180 		}
4181 #if 0
4182 		{
4183 			OSObject *      obj;
4184 			vm_offset_t     data;
4185 			vm_map_offset_t map_data;
4186 
4187 			if (propertiesCnt > sizeof(io_struct_inband_t)) {
4188 				return kIOReturnMessageTooLarge;
4189 			}
4190 
4191 			err = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) properties );
4192 			res = err;
4193 			data = CAST_DOWN(vm_offset_t, map_data);
4194 			if (KERN_SUCCESS == err) {
4195 				// must return success after vm_map_copyout() succeeds
4196 				obj = OSUnserializeXML((const char *) data, propertiesCnt );
4197 				vm_deallocate( kernel_map, data, propertiesCnt );
4198 				propertiesDict = OSDynamicCast(OSDictionary, obj);
4199 				if (!propertiesDict) {
4200 					res = kIOReturnBadArgument;
4201 					if (obj) {
4202 						obj->release();
4203 					}
4204 				}
4205 			}
4206 			if (kIOReturnSuccess != res) {
4207 				break;
4208 			}
4209 		}
4210 #endif
4211 		crossEndian = (ndr.int_rep != NDR_record.int_rep);
4212 		if (crossEndian) {
4213 			if (!propertiesDict) {
4214 				propertiesDict = OSDictionary::withCapacity(4);
4215 			}
4216 			OSData * data = OSData::withValue(ndr);
4217 			if (data) {
4218 				if (propertiesDict) {
4219 					propertiesDict->setObject(kIOUserClientCrossEndianKey, data);
4220 				}
4221 				data->release();
4222 			}
4223 		}
4224 
4225 		res = service->newUserClient( owningTask, (void *) owningTask,
4226 		    connect_type, propertiesDict, &client );
4227 
4228 		if (propertiesDict) {
4229 			propertiesDict->release();
4230 		}
4231 
4232 		if (res == kIOReturnSuccess && OSDynamicCast(IOUserClient, client) == NULL) {
4233 			// client should always be a IOUserClient
4234 			res = kIOReturnError;
4235 		}
4236 
4237 		if (res == kIOReturnSuccess) {
4238 			if (!client->reserved) {
4239 				if (!client->reserve()) {
4240 					client->clientClose();
4241 					OSSafeReleaseNULL(client);
4242 					res = kIOReturnNoMemory;
4243 				}
4244 			}
4245 		}
4246 
4247 		if (res == kIOReturnSuccess) {
4248 			client->sharedInstance = (NULL != client->getProperty(kIOUserClientSharedInstanceKey));
4249 			if (client->sharedInstance) {
4250 				IOLockLock(gIOUserClientOwnersLock);
4251 			}
4252 			if (!client->lock) {
4253 				client->lock       = IORWLockAlloc();
4254 				client->filterLock = IOLockAlloc();
4255 
4256 				client->messageAppSuspended = (NULL != client->getProperty(kIOUserClientMessageAppSuspendedKey));
4257 				{
4258 					OSObject * obj;
4259 					extern const OSSymbol * gIOSurfaceIdentifier;
4260 					obj = client->getProperty(kIOUserClientDefaultLockingKey);
4261 					if (obj) {
4262 						client->defaultLocking = (kOSBooleanFalse != client->getProperty(kIOUserClientDefaultLockingKey));
4263 					} else {
4264 						const OSMetaClass * meta;
4265 						OSKext            * kext;
4266 						meta = client->getMetaClass();
4267 						kext = meta->getKext();
4268 						if (!kext || !kext->hasDependency(gIOSurfaceIdentifier)) {
4269 							client->defaultLocking = true;
4270 							client->setProperty(kIOUserClientDefaultLockingKey, kOSBooleanTrue);
4271 						}
4272 					}
4273 				}
4274 			}
4275 			if (client->sharedInstance) {
4276 				IOLockUnlock(gIOUserClientOwnersLock);
4277 			}
4278 
4279 			disallowAccess = (crossEndian
4280 			    && (kOSBooleanTrue != service->getProperty(kIOUserClientCrossEndianCompatibleKey))
4281 			    && (kOSBooleanTrue != client->getProperty(kIOUserClientCrossEndianCompatibleKey)));
4282 			if (disallowAccess) {
4283 				res = kIOReturnUnsupported;
4284 			}
4285 #if CONFIG_MACF
4286 			else if (0 != mac_iokit_check_open(kauth_cred_get(), client, connect_type)) {
4287 				res = kIOReturnNotPermitted;
4288 			}
4289 #endif
4290 
4291 			if ((kIOReturnSuccess == res)
4292 			    && gIOUCFilterCallbacks
4293 			    && gIOUCFilterCallbacks->io_filter_resolver) {
4294 				io_filter_policy_t filterPolicy;
4295 				filterPolicy = client->filterForTask(owningTask, 0);
4296 				if (!filterPolicy) {
4297 					res = gIOUCFilterCallbacks->io_filter_resolver(owningTask, client, connect_type, &filterPolicy);
4298 					if (kIOReturnUnsupported == res) {
4299 						res = kIOReturnSuccess;
4300 					} else if (kIOReturnSuccess == res) {
4301 						client->filterForTask(owningTask, filterPolicy);
4302 					}
4303 				}
4304 			}
4305 
4306 			if (kIOReturnSuccess == res) {
4307 				res = client->registerOwner(owningTask);
4308 			}
4309 
4310 			if (kIOReturnSuccess != res) {
4311 				IOStatisticsClientCall();
4312 				client->clientClose();
4313 				client->release();
4314 				client = NULL;
4315 				break;
4316 			}
4317 			OSString * creatorName = IOCopyLogNameForPID(proc_selfpid());
4318 			if (creatorName) {
4319 				client->setProperty(kIOUserClientCreatorKey, creatorName);
4320 				creatorName->release();
4321 			}
4322 			client->setTerminateDefer(service, false);
4323 		}
4324 	}while (false);
4325 
4326 	*connection = client;
4327 	*result = res;
4328 
4329 	return err;
4330 }
4331 
4332 /* Routine io_service_close */
4333 kern_return_t
is_io_service_close(io_object_t connection)4334 is_io_service_close(
4335 	io_object_t connection )
4336 {
4337 	OSSet * mappings;
4338 	if ((mappings = OSDynamicCast(OSSet, connection))) {
4339 		return kIOReturnSuccess;
4340 	}
4341 
4342 	CHECK( IOUserClient, connection, client );
4343 
4344 	IOStatisticsClientCall();
4345 
4346 	if (client->sharedInstance || OSCompareAndSwap8(0, 1, &client->closed)) {
4347 		IORWLockWrite(client->lock);
4348 		client->clientClose();
4349 		IORWLockUnlock(client->lock);
4350 	} else {
4351 		IOLog("ignored is_io_service_close(0x%qx,%s)\n",
4352 		    client->getRegistryEntryID(), client->getName());
4353 	}
4354 
4355 	return kIOReturnSuccess;
4356 }
4357 
4358 /* Routine io_connect_get_service */
4359 kern_return_t
is_io_connect_get_service(io_object_t connection,io_object_t * service)4360 is_io_connect_get_service(
4361 	io_object_t connection,
4362 	io_object_t *service )
4363 {
4364 	IOService * theService;
4365 
4366 	CHECK( IOUserClient, connection, client );
4367 
4368 	theService = client->getService();
4369 	if (theService) {
4370 		theService->retain();
4371 	}
4372 
4373 	*service = theService;
4374 
4375 	return theService ? kIOReturnSuccess : kIOReturnUnsupported;
4376 }
4377 
4378 /* Routine io_connect_set_notification_port */
4379 kern_return_t
is_io_connect_set_notification_port(io_object_t connection,uint32_t notification_type,mach_port_t port,uint32_t reference)4380 is_io_connect_set_notification_port(
4381 	io_object_t connection,
4382 	uint32_t notification_type,
4383 	mach_port_t port,
4384 	uint32_t reference)
4385 {
4386 	kern_return_t ret;
4387 	CHECK( IOUserClient, connection, client );
4388 
4389 	IOStatisticsClientCall();
4390 	IORWLockWrite(client->lock);
4391 	ret = client->registerNotificationPort( port, notification_type,
4392 	    (io_user_reference_t) reference );
4393 	IORWLockUnlock(client->lock);
4394 	return ret;
4395 }
4396 
4397 /* Routine io_connect_set_notification_port */
4398 kern_return_t
is_io_connect_set_notification_port_64(io_object_t connection,uint32_t notification_type,mach_port_t port,io_user_reference_t reference)4399 is_io_connect_set_notification_port_64(
4400 	io_object_t connection,
4401 	uint32_t notification_type,
4402 	mach_port_t port,
4403 	io_user_reference_t reference)
4404 {
4405 	kern_return_t ret;
4406 	CHECK( IOUserClient, connection, client );
4407 
4408 	IOStatisticsClientCall();
4409 	IORWLockWrite(client->lock);
4410 	ret = client->registerNotificationPort( port, notification_type,
4411 	    reference );
4412 	IORWLockUnlock(client->lock);
4413 	return ret;
4414 }
4415 
4416 /* Routine io_connect_map_memory_into_task */
4417 kern_return_t
is_io_connect_map_memory_into_task(io_connect_t connection,uint32_t memory_type,task_t into_task,mach_vm_address_t * address,mach_vm_size_t * size,uint32_t flags)4418 is_io_connect_map_memory_into_task
4419 (
4420 	io_connect_t connection,
4421 	uint32_t memory_type,
4422 	task_t into_task,
4423 	mach_vm_address_t *address,
4424 	mach_vm_size_t *size,
4425 	uint32_t flags
4426 )
4427 {
4428 	IOReturn            err;
4429 	IOMemoryMap *       map;
4430 
4431 	CHECK( IOUserClient, connection, client );
4432 
4433 	if (!into_task) {
4434 		return kIOReturnBadArgument;
4435 	}
4436 
4437 	IOStatisticsClientCall();
4438 	if (client->defaultLocking) {
4439 		IORWLockWrite(client->lock);
4440 	}
4441 	map = client->mapClientMemory64( memory_type, into_task, flags, *address );
4442 	if (client->defaultLocking) {
4443 		IORWLockUnlock(client->lock);
4444 	}
4445 
4446 	if (map) {
4447 		*address = map->getAddress();
4448 		if (size) {
4449 			*size = map->getSize();
4450 		}
4451 
4452 		if (client->sharedInstance
4453 		    || (into_task != current_task())) {
4454 			// push a name out to the task owning the map,
4455 			// so we can clean up maps
4456 			mach_port_name_t name __unused =
4457 			    IOMachPort::makeSendRightForTask(
4458 				into_task, map, IKOT_IOKIT_OBJECT );
4459 			map->release();
4460 		} else {
4461 			// keep it with the user client
4462 			IOLockLock( gIOObjectPortLock);
4463 			if (NULL == client->mappings) {
4464 				client->mappings = OSSet::withCapacity(2);
4465 			}
4466 			if (client->mappings) {
4467 				client->mappings->setObject( map);
4468 			}
4469 			IOLockUnlock( gIOObjectPortLock);
4470 			map->release();
4471 		}
4472 		err = kIOReturnSuccess;
4473 	} else {
4474 		err = kIOReturnBadArgument;
4475 	}
4476 
4477 	return err;
4478 }
4479 
4480 /* Routine is_io_connect_map_memory */
4481 kern_return_t
is_io_connect_map_memory(io_object_t connect,uint32_t type,task_t task,uint32_t * mapAddr,uint32_t * mapSize,uint32_t flags)4482 is_io_connect_map_memory(
4483 	io_object_t     connect,
4484 	uint32_t        type,
4485 	task_t          task,
4486 	uint32_t  *     mapAddr,
4487 	uint32_t  *     mapSize,
4488 	uint32_t        flags )
4489 {
4490 	IOReturn          err;
4491 	mach_vm_address_t address;
4492 	mach_vm_size_t    size;
4493 
4494 	address = SCALAR64(*mapAddr);
4495 	size    = SCALAR64(*mapSize);
4496 
4497 	err = is_io_connect_map_memory_into_task(connect, type, task, &address, &size, flags);
4498 
4499 	*mapAddr = SCALAR32(address);
4500 	*mapSize = SCALAR32(size);
4501 
4502 	return err;
4503 }
4504 } /* extern "C" */
4505 
4506 IOMemoryMap *
removeMappingForDescriptor(IOMemoryDescriptor * mem)4507 IOUserClient::removeMappingForDescriptor(IOMemoryDescriptor * mem)
4508 {
4509 	OSIterator *  iter;
4510 	IOMemoryMap * map = NULL;
4511 
4512 	IOLockLock(gIOObjectPortLock);
4513 
4514 	iter = OSCollectionIterator::withCollection(mappings);
4515 	if (iter) {
4516 		while ((map = OSDynamicCast(IOMemoryMap, iter->getNextObject()))) {
4517 			if (mem == map->getMemoryDescriptor()) {
4518 				map->retain();
4519 				mappings->removeObject(map);
4520 				break;
4521 			}
4522 		}
4523 		iter->release();
4524 	}
4525 
4526 	IOLockUnlock(gIOObjectPortLock);
4527 
4528 	return map;
4529 }
4530 
4531 extern "C" {
4532 /* Routine io_connect_unmap_memory_from_task */
4533 kern_return_t
is_io_connect_unmap_memory_from_task(io_connect_t connection,uint32_t memory_type,task_t from_task,mach_vm_address_t address)4534 is_io_connect_unmap_memory_from_task
4535 (
4536 	io_connect_t connection,
4537 	uint32_t memory_type,
4538 	task_t from_task,
4539 	mach_vm_address_t address)
4540 {
4541 	IOReturn            err;
4542 	IOOptionBits        options = 0;
4543 	IOMemoryDescriptor * memory = NULL;
4544 	IOMemoryMap *       map;
4545 
4546 	CHECK( IOUserClient, connection, client );
4547 
4548 	if (!from_task) {
4549 		return kIOReturnBadArgument;
4550 	}
4551 
4552 	IOStatisticsClientCall();
4553 	if (client->defaultLocking) {
4554 		IORWLockWrite(client->lock);
4555 	}
4556 	err = client->clientMemoryForType((UInt32) memory_type, &options, &memory );
4557 	if (client->defaultLocking) {
4558 		IORWLockUnlock(client->lock);
4559 	}
4560 
4561 	if (memory && (kIOReturnSuccess == err)) {
4562 		options = (options & ~kIOMapUserOptionsMask)
4563 		    | kIOMapAnywhere | kIOMapReference;
4564 
4565 		map = memory->createMappingInTask( from_task, address, options );
4566 		memory->release();
4567 		if (map) {
4568 			IOLockLock( gIOObjectPortLock);
4569 			if (client->mappings) {
4570 				client->mappings->removeObject( map);
4571 			}
4572 			IOLockUnlock( gIOObjectPortLock);
4573 
4574 			mach_port_name_t name = 0;
4575 			bool is_shared_instance_or_from_current_task = from_task != current_task() || client->sharedInstance;
4576 			if (is_shared_instance_or_from_current_task) {
4577 				name = IOMachPort::makeSendRightForTask( from_task, map, IKOT_IOKIT_OBJECT );
4578 				map->release();
4579 			}
4580 
4581 			if (name) {
4582 				map->userClientUnmap();
4583 				err = iokit_mod_send_right( from_task, name, -2 );
4584 				err = kIOReturnSuccess;
4585 			} else {
4586 				IOMachPort::releasePortForObject( map, IKOT_IOKIT_OBJECT );
4587 			}
4588 			if (!is_shared_instance_or_from_current_task) {
4589 				map->release();
4590 			}
4591 		} else {
4592 			err = kIOReturnBadArgument;
4593 		}
4594 	}
4595 
4596 	return err;
4597 }
4598 
4599 kern_return_t
is_io_connect_unmap_memory(io_object_t connect,uint32_t type,task_t task,uint32_t mapAddr)4600 is_io_connect_unmap_memory(
4601 	io_object_t     connect,
4602 	uint32_t        type,
4603 	task_t          task,
4604 	uint32_t        mapAddr )
4605 {
4606 	IOReturn            err;
4607 	mach_vm_address_t   address;
4608 
4609 	address = SCALAR64(mapAddr);
4610 
4611 	err = is_io_connect_unmap_memory_from_task(connect, type, task, mapAddr);
4612 
4613 	return err;
4614 }
4615 
4616 
4617 /* Routine io_connect_add_client */
4618 kern_return_t
is_io_connect_add_client(io_object_t connection,io_object_t connect_to)4619 is_io_connect_add_client(
4620 	io_object_t connection,
4621 	io_object_t connect_to)
4622 {
4623 	CHECK( IOUserClient, connection, client );
4624 	CHECK( IOUserClient, connect_to, to );
4625 
4626 	IOReturn ret;
4627 
4628 	IOStatisticsClientCall();
4629 	if (client->defaultLocking) {
4630 		IORWLockWrite(client->lock);
4631 	}
4632 	ret = client->connectClient( to );
4633 	if (client->defaultLocking) {
4634 		IORWLockUnlock(client->lock);
4635 	}
4636 	return ret;
4637 }
4638 
4639 
4640 /* Routine io_connect_set_properties */
4641 kern_return_t
is_io_connect_set_properties(io_object_t connection,io_buf_ptr_t properties,mach_msg_type_number_t propertiesCnt,kern_return_t * result)4642 is_io_connect_set_properties(
4643 	io_object_t connection,
4644 	io_buf_ptr_t properties,
4645 	mach_msg_type_number_t propertiesCnt,
4646 	kern_return_t * result)
4647 {
4648 	return is_io_registry_entry_set_properties( connection, properties, propertiesCnt, result );
4649 }
4650 
4651 /* Routine io_user_client_method */
4652 kern_return_t
is_io_connect_method_var_output(io_connect_t connection,uint32_t selector,io_scalar_inband64_t scalar_input,mach_msg_type_number_t scalar_inputCnt,io_struct_inband_t inband_input,mach_msg_type_number_t inband_inputCnt,mach_vm_address_t ool_input,mach_vm_size_t ool_input_size,io_struct_inband_t inband_output,mach_msg_type_number_t * inband_outputCnt,io_scalar_inband64_t scalar_output,mach_msg_type_number_t * scalar_outputCnt,io_buf_ptr_t * var_output,mach_msg_type_number_t * var_outputCnt)4653 is_io_connect_method_var_output
4654 (
4655 	io_connect_t connection,
4656 	uint32_t selector,
4657 	io_scalar_inband64_t scalar_input,
4658 	mach_msg_type_number_t scalar_inputCnt,
4659 	io_struct_inband_t inband_input,
4660 	mach_msg_type_number_t inband_inputCnt,
4661 	mach_vm_address_t ool_input,
4662 	mach_vm_size_t ool_input_size,
4663 	io_struct_inband_t inband_output,
4664 	mach_msg_type_number_t *inband_outputCnt,
4665 	io_scalar_inband64_t scalar_output,
4666 	mach_msg_type_number_t *scalar_outputCnt,
4667 	io_buf_ptr_t *var_output,
4668 	mach_msg_type_number_t *var_outputCnt
4669 )
4670 {
4671 	CHECK( IOUserClient, connection, client );
4672 
4673 	IOExternalMethodArguments args;
4674 	IOReturn ret;
4675 	IOMemoryDescriptor * inputMD  = NULL;
4676 	OSObject *           structureVariableOutputData = NULL;
4677 
4678 	bzero(&args.__reserved[0], sizeof(args.__reserved));
4679 	args.__reservedA = 0;
4680 	args.version = kIOExternalMethodArgumentsCurrentVersion;
4681 
4682 	args.selector = selector;
4683 
4684 	args.asyncWakePort               = MACH_PORT_NULL;
4685 	args.asyncReference              = NULL;
4686 	args.asyncReferenceCount         = 0;
4687 	args.structureVariableOutputData = &structureVariableOutputData;
4688 
4689 	args.scalarInput = scalar_input;
4690 	args.scalarInputCount = scalar_inputCnt;
4691 	args.structureInput = inband_input;
4692 	args.structureInputSize = inband_inputCnt;
4693 
4694 	if (ool_input && (ool_input_size <= sizeof(io_struct_inband_t))) {
4695 		return kIOReturnIPCError;
4696 	}
4697 
4698 	if (ool_input) {
4699 		inputMD = IOMemoryDescriptor::withAddressRange(ool_input, ool_input_size,
4700 		    kIODirectionOut | kIOMemoryMapCopyOnWrite,
4701 		    current_task());
4702 	}
4703 
4704 	args.structureInputDescriptor = inputMD;
4705 
4706 	args.scalarOutput = scalar_output;
4707 	args.scalarOutputCount = *scalar_outputCnt;
4708 	bzero(&scalar_output[0], *scalar_outputCnt * sizeof(scalar_output[0]));
4709 	args.structureOutput = inband_output;
4710 	args.structureOutputSize = *inband_outputCnt;
4711 	args.structureOutputDescriptor = NULL;
4712 	args.structureOutputDescriptorSize = 0;
4713 
4714 	IOStatisticsClientCall();
4715 	ret = kIOReturnSuccess;
4716 
4717 	io_filter_policy_t filterPolicy = client->filterForTask(current_task(), 0);
4718 	if (filterPolicy && gIOUCFilterCallbacks->io_filter_applier) {
4719 		ret = gIOUCFilterCallbacks->io_filter_applier(client, filterPolicy, io_filter_type_external_method, selector);
4720 	}
4721 	if (kIOReturnSuccess == ret) {
4722 		if (client->defaultLocking) {
4723 			IORWLockRead(client->lock);
4724 		}
4725 		ret = client->externalMethod( selector, &args );
4726 		if (client->defaultLocking) {
4727 			IORWLockUnlock(client->lock);
4728 		}
4729 	}
4730 
4731 	*scalar_outputCnt = args.scalarOutputCount;
4732 	*inband_outputCnt = args.structureOutputSize;
4733 
4734 	if (var_outputCnt && var_output && (kIOReturnSuccess == ret)) {
4735 		OSSerialize * serialize;
4736 		OSData      * data;
4737 		unsigned int  len;
4738 
4739 		if ((serialize = OSDynamicCast(OSSerialize, structureVariableOutputData))) {
4740 			len = serialize->getLength();
4741 			*var_outputCnt = len;
4742 			ret = copyoutkdata(serialize->text(), len, var_output);
4743 		} else if ((data = OSDynamicCast(OSData, structureVariableOutputData))) {
4744 			data->clipForCopyout();
4745 			len = data->getLength();
4746 			*var_outputCnt = len;
4747 			ret = copyoutkdata(data->getBytesNoCopy(), len, var_output);
4748 		} else {
4749 			ret = kIOReturnUnderrun;
4750 		}
4751 	}
4752 
4753 	if (inputMD) {
4754 		inputMD->release();
4755 	}
4756 	if (structureVariableOutputData) {
4757 		structureVariableOutputData->release();
4758 	}
4759 
4760 	return ret;
4761 }
4762 
4763 /* Routine io_user_client_method */
4764 kern_return_t
is_io_connect_method(io_connect_t connection,uint32_t selector,io_scalar_inband64_t scalar_input,mach_msg_type_number_t scalar_inputCnt,io_struct_inband_t inband_input,mach_msg_type_number_t inband_inputCnt,mach_vm_address_t ool_input,mach_vm_size_t ool_input_size,io_struct_inband_t inband_output,mach_msg_type_number_t * inband_outputCnt,io_scalar_inband64_t scalar_output,mach_msg_type_number_t * scalar_outputCnt,mach_vm_address_t ool_output,mach_vm_size_t * ool_output_size)4765 is_io_connect_method
4766 (
4767 	io_connect_t connection,
4768 	uint32_t selector,
4769 	io_scalar_inband64_t scalar_input,
4770 	mach_msg_type_number_t scalar_inputCnt,
4771 	io_struct_inband_t inband_input,
4772 	mach_msg_type_number_t inband_inputCnt,
4773 	mach_vm_address_t ool_input,
4774 	mach_vm_size_t ool_input_size,
4775 	io_struct_inband_t inband_output,
4776 	mach_msg_type_number_t *inband_outputCnt,
4777 	io_scalar_inband64_t scalar_output,
4778 	mach_msg_type_number_t *scalar_outputCnt,
4779 	mach_vm_address_t ool_output,
4780 	mach_vm_size_t *ool_output_size
4781 )
4782 {
4783 	CHECK( IOUserClient, connection, client );
4784 
4785 	IOExternalMethodArguments args;
4786 	IOReturn ret;
4787 	IOMemoryDescriptor * inputMD  = NULL;
4788 	IOMemoryDescriptor * outputMD = NULL;
4789 
4790 	bzero(&args.__reserved[0], sizeof(args.__reserved));
4791 	args.__reservedA = 0;
4792 	args.version = kIOExternalMethodArgumentsCurrentVersion;
4793 
4794 	args.selector = selector;
4795 
4796 	args.asyncWakePort               = MACH_PORT_NULL;
4797 	args.asyncReference              = NULL;
4798 	args.asyncReferenceCount         = 0;
4799 	args.structureVariableOutputData = NULL;
4800 
4801 	args.scalarInput = scalar_input;
4802 	args.scalarInputCount = scalar_inputCnt;
4803 	args.structureInput = inband_input;
4804 	args.structureInputSize = inband_inputCnt;
4805 
4806 	if (ool_input && (ool_input_size <= sizeof(io_struct_inband_t))) {
4807 		return kIOReturnIPCError;
4808 	}
4809 	if (ool_output) {
4810 		if (*ool_output_size <= sizeof(io_struct_inband_t)) {
4811 			return kIOReturnIPCError;
4812 		}
4813 		if (*ool_output_size > UINT_MAX) {
4814 			return kIOReturnIPCError;
4815 		}
4816 	}
4817 
4818 	if (ool_input) {
4819 		inputMD = IOMemoryDescriptor::withAddressRange(ool_input, ool_input_size,
4820 		    kIODirectionOut | kIOMemoryMapCopyOnWrite,
4821 		    current_task());
4822 	}
4823 
4824 	args.structureInputDescriptor = inputMD;
4825 
4826 	args.scalarOutput = scalar_output;
4827 	args.scalarOutputCount = *scalar_outputCnt;
4828 	bzero(&scalar_output[0], *scalar_outputCnt * sizeof(scalar_output[0]));
4829 	args.structureOutput = inband_output;
4830 	args.structureOutputSize = *inband_outputCnt;
4831 
4832 	if (ool_output && ool_output_size) {
4833 		outputMD = IOMemoryDescriptor::withAddressRange(ool_output, *ool_output_size,
4834 		    kIODirectionIn, current_task());
4835 	}
4836 
4837 	args.structureOutputDescriptor = outputMD;
4838 	args.structureOutputDescriptorSize = ool_output_size
4839 	    ? ((typeof(args.structureOutputDescriptorSize)) * ool_output_size)
4840 	    : 0;
4841 
4842 	IOStatisticsClientCall();
4843 	ret = kIOReturnSuccess;
4844 	io_filter_policy_t filterPolicy = client->filterForTask(current_task(), 0);
4845 	if (filterPolicy && gIOUCFilterCallbacks->io_filter_applier) {
4846 		ret = gIOUCFilterCallbacks->io_filter_applier(client, filterPolicy, io_filter_type_external_method, selector);
4847 	}
4848 	if (kIOReturnSuccess == ret) {
4849 		if (client->defaultLocking) {
4850 			IORWLockRead(client->lock);
4851 		}
4852 		ret = client->externalMethod( selector, &args );
4853 		if (client->defaultLocking) {
4854 			IORWLockUnlock(client->lock);
4855 		}
4856 	}
4857 
4858 	*scalar_outputCnt = args.scalarOutputCount;
4859 	*inband_outputCnt = args.structureOutputSize;
4860 	*ool_output_size  = args.structureOutputDescriptorSize;
4861 
4862 	if (inputMD) {
4863 		inputMD->release();
4864 	}
4865 	if (outputMD) {
4866 		outputMD->release();
4867 	}
4868 
4869 	return ret;
4870 }
4871 
4872 /* Routine io_async_user_client_method */
4873 kern_return_t
is_io_connect_async_method(io_connect_t connection,mach_port_t wake_port,io_async_ref64_t reference,mach_msg_type_number_t referenceCnt,uint32_t selector,io_scalar_inband64_t scalar_input,mach_msg_type_number_t scalar_inputCnt,io_struct_inband_t inband_input,mach_msg_type_number_t inband_inputCnt,mach_vm_address_t ool_input,mach_vm_size_t ool_input_size,io_struct_inband_t inband_output,mach_msg_type_number_t * inband_outputCnt,io_scalar_inband64_t scalar_output,mach_msg_type_number_t * scalar_outputCnt,mach_vm_address_t ool_output,mach_vm_size_t * ool_output_size)4874 is_io_connect_async_method
4875 (
4876 	io_connect_t connection,
4877 	mach_port_t wake_port,
4878 	io_async_ref64_t reference,
4879 	mach_msg_type_number_t referenceCnt,
4880 	uint32_t selector,
4881 	io_scalar_inband64_t scalar_input,
4882 	mach_msg_type_number_t scalar_inputCnt,
4883 	io_struct_inband_t inband_input,
4884 	mach_msg_type_number_t inband_inputCnt,
4885 	mach_vm_address_t ool_input,
4886 	mach_vm_size_t ool_input_size,
4887 	io_struct_inband_t inband_output,
4888 	mach_msg_type_number_t *inband_outputCnt,
4889 	io_scalar_inband64_t scalar_output,
4890 	mach_msg_type_number_t *scalar_outputCnt,
4891 	mach_vm_address_t ool_output,
4892 	mach_vm_size_t * ool_output_size
4893 )
4894 {
4895 	CHECK( IOUserClient, connection, client );
4896 
4897 	IOExternalMethodArguments args;
4898 	IOReturn ret;
4899 	IOMemoryDescriptor * inputMD  = NULL;
4900 	IOMemoryDescriptor * outputMD = NULL;
4901 
4902 	if (referenceCnt < 1) {
4903 		return kIOReturnBadArgument;
4904 	}
4905 
4906 	bzero(&args.__reserved[0], sizeof(args.__reserved));
4907 	args.__reservedA = 0;
4908 	args.version = kIOExternalMethodArgumentsCurrentVersion;
4909 
4910 	reference[0]             = (io_user_reference_t) wake_port;
4911 	if (vm_map_is_64bit(get_task_map(current_task()))) {
4912 		reference[0]         |= kIOUCAsync64Flag;
4913 	}
4914 
4915 	args.selector = selector;
4916 
4917 	args.asyncWakePort       = wake_port;
4918 	args.asyncReference      = reference;
4919 	args.asyncReferenceCount = referenceCnt;
4920 
4921 	args.structureVariableOutputData = NULL;
4922 
4923 	args.scalarInput = scalar_input;
4924 	args.scalarInputCount = scalar_inputCnt;
4925 	args.structureInput = inband_input;
4926 	args.structureInputSize = inband_inputCnt;
4927 
4928 	if (ool_input && (ool_input_size <= sizeof(io_struct_inband_t))) {
4929 		return kIOReturnIPCError;
4930 	}
4931 	if (ool_output) {
4932 		if (*ool_output_size <= sizeof(io_struct_inband_t)) {
4933 			return kIOReturnIPCError;
4934 		}
4935 		if (*ool_output_size > UINT_MAX) {
4936 			return kIOReturnIPCError;
4937 		}
4938 	}
4939 
4940 	if (ool_input) {
4941 		inputMD = IOMemoryDescriptor::withAddressRange(ool_input, ool_input_size,
4942 		    kIODirectionOut | kIOMemoryMapCopyOnWrite,
4943 		    current_task());
4944 	}
4945 
4946 	args.structureInputDescriptor = inputMD;
4947 
4948 	args.scalarOutput = scalar_output;
4949 	args.scalarOutputCount = *scalar_outputCnt;
4950 	bzero(&scalar_output[0], *scalar_outputCnt * sizeof(scalar_output[0]));
4951 	args.structureOutput = inband_output;
4952 	args.structureOutputSize = *inband_outputCnt;
4953 
4954 	if (ool_output) {
4955 		outputMD = IOMemoryDescriptor::withAddressRange(ool_output, *ool_output_size,
4956 		    kIODirectionIn, current_task());
4957 	}
4958 
4959 	args.structureOutputDescriptor = outputMD;
4960 	args.structureOutputDescriptorSize = ((typeof(args.structureOutputDescriptorSize)) * ool_output_size);
4961 
4962 	IOStatisticsClientCall();
4963 	ret = kIOReturnSuccess;
4964 	io_filter_policy_t filterPolicy = client->filterForTask(current_task(), 0);
4965 	if (filterPolicy && gIOUCFilterCallbacks->io_filter_applier) {
4966 		ret = gIOUCFilterCallbacks->io_filter_applier(client, filterPolicy, io_filter_type_external_async_method, selector);
4967 	}
4968 	if (kIOReturnSuccess == ret) {
4969 		if (client->defaultLocking) {
4970 			IORWLockRead(client->lock);
4971 		}
4972 		ret = client->externalMethod( selector, &args );
4973 		if (client->defaultLocking) {
4974 			IORWLockUnlock(client->lock);
4975 		}
4976 	}
4977 
4978 	*scalar_outputCnt = args.scalarOutputCount;
4979 	*inband_outputCnt = args.structureOutputSize;
4980 	*ool_output_size  = args.structureOutputDescriptorSize;
4981 
4982 	if (inputMD) {
4983 		inputMD->release();
4984 	}
4985 	if (outputMD) {
4986 		outputMD->release();
4987 	}
4988 
4989 	return ret;
4990 }
4991 
4992 /* Routine io_connect_method_scalarI_scalarO */
4993 kern_return_t
is_io_connect_method_scalarI_scalarO(io_object_t connect,uint32_t index,io_scalar_inband_t input,mach_msg_type_number_t inputCount,io_scalar_inband_t output,mach_msg_type_number_t * outputCount)4994 is_io_connect_method_scalarI_scalarO(
4995 	io_object_t        connect,
4996 	uint32_t           index,
4997 	io_scalar_inband_t       input,
4998 	mach_msg_type_number_t   inputCount,
4999 	io_scalar_inband_t       output,
5000 	mach_msg_type_number_t * outputCount )
5001 {
5002 	IOReturn err;
5003 	uint32_t i;
5004 	io_scalar_inband64_t _input;
5005 	io_scalar_inband64_t _output;
5006 
5007 	mach_msg_type_number_t struct_outputCnt = 0;
5008 	mach_vm_size_t ool_output_size = 0;
5009 
5010 	bzero(&_output[0], sizeof(_output));
5011 	for (i = 0; i < inputCount; i++) {
5012 		_input[i] = SCALAR64(input[i]);
5013 	}
5014 
5015 	err = is_io_connect_method(connect, index,
5016 	    _input, inputCount,
5017 	    NULL, 0,
5018 	    0, 0,
5019 	    NULL, &struct_outputCnt,
5020 	    _output, outputCount,
5021 	    0, &ool_output_size);
5022 
5023 	for (i = 0; i < *outputCount; i++) {
5024 		output[i] = SCALAR32(_output[i]);
5025 	}
5026 
5027 	return err;
5028 }
5029 
5030 kern_return_t
shim_io_connect_method_scalarI_scalarO(IOExternalMethod * method,IOService * object,const io_user_scalar_t * input,mach_msg_type_number_t inputCount,io_user_scalar_t * output,mach_msg_type_number_t * outputCount)5031 shim_io_connect_method_scalarI_scalarO(
5032 	IOExternalMethod *      method,
5033 	IOService *             object,
5034 	const io_user_scalar_t * input,
5035 	mach_msg_type_number_t   inputCount,
5036 	io_user_scalar_t * output,
5037 	mach_msg_type_number_t * outputCount )
5038 {
5039 	IOMethod            func;
5040 	io_scalar_inband_t  _output;
5041 	IOReturn            err;
5042 	err = kIOReturnBadArgument;
5043 
5044 	bzero(&_output[0], sizeof(_output));
5045 	do {
5046 		if (inputCount != method->count0) {
5047 			IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0);
5048 			DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0);
5049 			continue;
5050 		}
5051 		if (*outputCount != method->count1) {
5052 			IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)*outputCount, (uint64_t)method->count1);
5053 			DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)*outputCount, uint64_t, (uint64_t)method->count1);
5054 			continue;
5055 		}
5056 
5057 		func = method->func;
5058 
5059 		switch (inputCount) {
5060 		case 6:
5061 			err = (object->*func)(  ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5062 			    ARG32(input[3]), ARG32(input[4]), ARG32(input[5]));
5063 			break;
5064 		case 5:
5065 			err = (object->*func)(  ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5066 			    ARG32(input[3]), ARG32(input[4]),
5067 			    &_output[0] );
5068 			break;
5069 		case 4:
5070 			err = (object->*func)(  ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5071 			    ARG32(input[3]),
5072 			    &_output[0], &_output[1] );
5073 			break;
5074 		case 3:
5075 			err = (object->*func)(  ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5076 			    &_output[0], &_output[1], &_output[2] );
5077 			break;
5078 		case 2:
5079 			err = (object->*func)(  ARG32(input[0]), ARG32(input[1]),
5080 			    &_output[0], &_output[1], &_output[2],
5081 			    &_output[3] );
5082 			break;
5083 		case 1:
5084 			err = (object->*func)(  ARG32(input[0]),
5085 			    &_output[0], &_output[1], &_output[2],
5086 			    &_output[3], &_output[4] );
5087 			break;
5088 		case 0:
5089 			err = (object->*func)(  &_output[0], &_output[1], &_output[2],
5090 			    &_output[3], &_output[4], &_output[5] );
5091 			break;
5092 
5093 		default:
5094 			IOLog("%s: Bad method table\n", object->getName());
5095 		}
5096 	}while (false);
5097 
5098 	uint32_t i;
5099 	for (i = 0; i < *outputCount; i++) {
5100 		output[i] = SCALAR32(_output[i]);
5101 	}
5102 
5103 	return err;
5104 }
5105 
5106 /* Routine io_async_method_scalarI_scalarO */
5107 kern_return_t
is_io_async_method_scalarI_scalarO(io_object_t connect,mach_port_t wake_port,io_async_ref_t reference,mach_msg_type_number_t referenceCnt,uint32_t index,io_scalar_inband_t input,mach_msg_type_number_t inputCount,io_scalar_inband_t output,mach_msg_type_number_t * outputCount)5108 is_io_async_method_scalarI_scalarO(
5109 	io_object_t        connect,
5110 	mach_port_t wake_port,
5111 	io_async_ref_t reference,
5112 	mach_msg_type_number_t referenceCnt,
5113 	uint32_t           index,
5114 	io_scalar_inband_t       input,
5115 	mach_msg_type_number_t   inputCount,
5116 	io_scalar_inband_t       output,
5117 	mach_msg_type_number_t * outputCount )
5118 {
5119 	IOReturn err;
5120 	uint32_t i;
5121 	io_scalar_inband64_t _input;
5122 	io_scalar_inband64_t _output;
5123 	io_async_ref64_t _reference;
5124 
5125 	if (referenceCnt > ASYNC_REF64_COUNT) {
5126 		return kIOReturnBadArgument;
5127 	}
5128 	bzero(&_output[0], sizeof(_output));
5129 	for (i = 0; i < referenceCnt; i++) {
5130 		_reference[i] = REF64(reference[i]);
5131 	}
5132 	bzero(&_reference[referenceCnt], (ASYNC_REF64_COUNT - referenceCnt) * sizeof(_reference[0]));
5133 
5134 	mach_msg_type_number_t struct_outputCnt = 0;
5135 	mach_vm_size_t ool_output_size = 0;
5136 
5137 	for (i = 0; i < inputCount; i++) {
5138 		_input[i] = SCALAR64(input[i]);
5139 	}
5140 
5141 	err = is_io_connect_async_method(connect,
5142 	    wake_port, _reference, referenceCnt,
5143 	    index,
5144 	    _input, inputCount,
5145 	    NULL, 0,
5146 	    0, 0,
5147 	    NULL, &struct_outputCnt,
5148 	    _output, outputCount,
5149 	    0, &ool_output_size);
5150 
5151 	for (i = 0; i < *outputCount; i++) {
5152 		output[i] = SCALAR32(_output[i]);
5153 	}
5154 
5155 	return err;
5156 }
5157 /* Routine io_async_method_scalarI_structureO */
5158 kern_return_t
is_io_async_method_scalarI_structureO(io_object_t connect,mach_port_t wake_port,io_async_ref_t reference,mach_msg_type_number_t referenceCnt,uint32_t index,io_scalar_inband_t input,mach_msg_type_number_t inputCount,io_struct_inband_t output,mach_msg_type_number_t * outputCount)5159 is_io_async_method_scalarI_structureO(
5160 	io_object_t     connect,
5161 	mach_port_t wake_port,
5162 	io_async_ref_t reference,
5163 	mach_msg_type_number_t referenceCnt,
5164 	uint32_t        index,
5165 	io_scalar_inband_t input,
5166 	mach_msg_type_number_t  inputCount,
5167 	io_struct_inband_t              output,
5168 	mach_msg_type_number_t *        outputCount )
5169 {
5170 	uint32_t i;
5171 	io_scalar_inband64_t _input;
5172 	io_async_ref64_t _reference;
5173 
5174 	if (referenceCnt > ASYNC_REF64_COUNT) {
5175 		return kIOReturnBadArgument;
5176 	}
5177 	for (i = 0; i < referenceCnt; i++) {
5178 		_reference[i] = REF64(reference[i]);
5179 	}
5180 	bzero(&_reference[referenceCnt], (ASYNC_REF64_COUNT - referenceCnt) * sizeof(_reference[0]));
5181 
5182 	mach_msg_type_number_t scalar_outputCnt = 0;
5183 	mach_vm_size_t ool_output_size = 0;
5184 
5185 	for (i = 0; i < inputCount; i++) {
5186 		_input[i] = SCALAR64(input[i]);
5187 	}
5188 
5189 	return is_io_connect_async_method(connect,
5190 	           wake_port, _reference, referenceCnt,
5191 	           index,
5192 	           _input, inputCount,
5193 	           NULL, 0,
5194 	           0, 0,
5195 	           output, outputCount,
5196 	           NULL, &scalar_outputCnt,
5197 	           0, &ool_output_size);
5198 }
5199 
5200 /* Routine io_async_method_scalarI_structureI */
5201 kern_return_t
is_io_async_method_scalarI_structureI(io_connect_t connect,mach_port_t wake_port,io_async_ref_t reference,mach_msg_type_number_t referenceCnt,uint32_t index,io_scalar_inband_t input,mach_msg_type_number_t inputCount,io_struct_inband_t inputStruct,mach_msg_type_number_t inputStructCount)5202 is_io_async_method_scalarI_structureI(
5203 	io_connect_t            connect,
5204 	mach_port_t wake_port,
5205 	io_async_ref_t reference,
5206 	mach_msg_type_number_t referenceCnt,
5207 	uint32_t                index,
5208 	io_scalar_inband_t      input,
5209 	mach_msg_type_number_t  inputCount,
5210 	io_struct_inband_t      inputStruct,
5211 	mach_msg_type_number_t  inputStructCount )
5212 {
5213 	uint32_t i;
5214 	io_scalar_inband64_t _input;
5215 	io_async_ref64_t _reference;
5216 
5217 	if (referenceCnt > ASYNC_REF64_COUNT) {
5218 		return kIOReturnBadArgument;
5219 	}
5220 	for (i = 0; i < referenceCnt; i++) {
5221 		_reference[i] = REF64(reference[i]);
5222 	}
5223 	bzero(&_reference[referenceCnt], (ASYNC_REF64_COUNT - referenceCnt) * sizeof(_reference[0]));
5224 
5225 	mach_msg_type_number_t scalar_outputCnt = 0;
5226 	mach_msg_type_number_t inband_outputCnt = 0;
5227 	mach_vm_size_t ool_output_size = 0;
5228 
5229 	for (i = 0; i < inputCount; i++) {
5230 		_input[i] = SCALAR64(input[i]);
5231 	}
5232 
5233 	return is_io_connect_async_method(connect,
5234 	           wake_port, _reference, referenceCnt,
5235 	           index,
5236 	           _input, inputCount,
5237 	           inputStruct, inputStructCount,
5238 	           0, 0,
5239 	           NULL, &inband_outputCnt,
5240 	           NULL, &scalar_outputCnt,
5241 	           0, &ool_output_size);
5242 }
5243 
5244 /* Routine io_async_method_structureI_structureO */
5245 kern_return_t
is_io_async_method_structureI_structureO(io_object_t connect,mach_port_t wake_port,io_async_ref_t reference,mach_msg_type_number_t referenceCnt,uint32_t index,io_struct_inband_t input,mach_msg_type_number_t inputCount,io_struct_inband_t output,mach_msg_type_number_t * outputCount)5246 is_io_async_method_structureI_structureO(
5247 	io_object_t     connect,
5248 	mach_port_t wake_port,
5249 	io_async_ref_t reference,
5250 	mach_msg_type_number_t referenceCnt,
5251 	uint32_t        index,
5252 	io_struct_inband_t              input,
5253 	mach_msg_type_number_t  inputCount,
5254 	io_struct_inband_t              output,
5255 	mach_msg_type_number_t *        outputCount )
5256 {
5257 	uint32_t i;
5258 	mach_msg_type_number_t scalar_outputCnt = 0;
5259 	mach_vm_size_t ool_output_size = 0;
5260 	io_async_ref64_t _reference;
5261 
5262 	if (referenceCnt > ASYNC_REF64_COUNT) {
5263 		return kIOReturnBadArgument;
5264 	}
5265 	for (i = 0; i < referenceCnt; i++) {
5266 		_reference[i] = REF64(reference[i]);
5267 	}
5268 	bzero(&_reference[referenceCnt], (ASYNC_REF64_COUNT - referenceCnt) * sizeof(_reference[0]));
5269 
5270 	return is_io_connect_async_method(connect,
5271 	           wake_port, _reference, referenceCnt,
5272 	           index,
5273 	           NULL, 0,
5274 	           input, inputCount,
5275 	           0, 0,
5276 	           output, outputCount,
5277 	           NULL, &scalar_outputCnt,
5278 	           0, &ool_output_size);
5279 }
5280 
5281 
5282 kern_return_t
shim_io_async_method_scalarI_scalarO(IOExternalAsyncMethod * method,IOService * object,mach_port_t asyncWakePort,io_user_reference_t * asyncReference,uint32_t asyncReferenceCount,const io_user_scalar_t * input,mach_msg_type_number_t inputCount,io_user_scalar_t * output,mach_msg_type_number_t * outputCount)5283 shim_io_async_method_scalarI_scalarO(
5284 	IOExternalAsyncMethod * method,
5285 	IOService *             object,
5286 	mach_port_t             asyncWakePort,
5287 	io_user_reference_t *   asyncReference,
5288 	uint32_t                asyncReferenceCount,
5289 	const io_user_scalar_t * input,
5290 	mach_msg_type_number_t   inputCount,
5291 	io_user_scalar_t * output,
5292 	mach_msg_type_number_t * outputCount )
5293 {
5294 	IOAsyncMethod       func;
5295 	uint32_t            i;
5296 	io_scalar_inband_t  _output;
5297 	IOReturn            err;
5298 	io_async_ref_t      reference;
5299 
5300 	bzero(&_output[0], sizeof(_output));
5301 	for (i = 0; i < asyncReferenceCount; i++) {
5302 		reference[i] = REF32(asyncReference[i]);
5303 	}
5304 
5305 	err = kIOReturnBadArgument;
5306 
5307 	do {
5308 		if (inputCount != method->count0) {
5309 			IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0);
5310 			DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0);
5311 			continue;
5312 		}
5313 		if (*outputCount != method->count1) {
5314 			IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)*outputCount, (uint64_t)method->count1);
5315 			DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)*outputCount, uint64_t, (uint64_t)method->count1);
5316 			continue;
5317 		}
5318 
5319 		func = method->func;
5320 
5321 		switch (inputCount) {
5322 		case 6:
5323 			err = (object->*func)(  reference,
5324 			    ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5325 			    ARG32(input[3]), ARG32(input[4]), ARG32(input[5]));
5326 			break;
5327 		case 5:
5328 			err = (object->*func)(  reference,
5329 			    ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5330 			    ARG32(input[3]), ARG32(input[4]),
5331 			    &_output[0] );
5332 			break;
5333 		case 4:
5334 			err = (object->*func)(  reference,
5335 			    ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5336 			    ARG32(input[3]),
5337 			    &_output[0], &_output[1] );
5338 			break;
5339 		case 3:
5340 			err = (object->*func)(  reference,
5341 			    ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5342 			    &_output[0], &_output[1], &_output[2] );
5343 			break;
5344 		case 2:
5345 			err = (object->*func)(  reference,
5346 			    ARG32(input[0]), ARG32(input[1]),
5347 			    &_output[0], &_output[1], &_output[2],
5348 			    &_output[3] );
5349 			break;
5350 		case 1:
5351 			err = (object->*func)(  reference,
5352 			    ARG32(input[0]),
5353 			    &_output[0], &_output[1], &_output[2],
5354 			    &_output[3], &_output[4] );
5355 			break;
5356 		case 0:
5357 			err = (object->*func)(  reference,
5358 			    &_output[0], &_output[1], &_output[2],
5359 			    &_output[3], &_output[4], &_output[5] );
5360 			break;
5361 
5362 		default:
5363 			IOLog("%s: Bad method table\n", object->getName());
5364 		}
5365 	}while (false);
5366 
5367 	for (i = 0; i < *outputCount; i++) {
5368 		output[i] = SCALAR32(_output[i]);
5369 	}
5370 
5371 	return err;
5372 }
5373 
5374 
5375 /* Routine io_connect_method_scalarI_structureO */
5376 kern_return_t
is_io_connect_method_scalarI_structureO(io_object_t connect,uint32_t index,io_scalar_inband_t input,mach_msg_type_number_t inputCount,io_struct_inband_t output,mach_msg_type_number_t * outputCount)5377 is_io_connect_method_scalarI_structureO(
5378 	io_object_t     connect,
5379 	uint32_t        index,
5380 	io_scalar_inband_t input,
5381 	mach_msg_type_number_t  inputCount,
5382 	io_struct_inband_t              output,
5383 	mach_msg_type_number_t *        outputCount )
5384 {
5385 	uint32_t i;
5386 	io_scalar_inband64_t _input;
5387 
5388 	mach_msg_type_number_t scalar_outputCnt = 0;
5389 	mach_vm_size_t ool_output_size = 0;
5390 
5391 	for (i = 0; i < inputCount; i++) {
5392 		_input[i] = SCALAR64(input[i]);
5393 	}
5394 
5395 	return is_io_connect_method(connect, index,
5396 	           _input, inputCount,
5397 	           NULL, 0,
5398 	           0, 0,
5399 	           output, outputCount,
5400 	           NULL, &scalar_outputCnt,
5401 	           0, &ool_output_size);
5402 }
5403 
5404 kern_return_t
shim_io_connect_method_scalarI_structureO(IOExternalMethod * method,IOService * object,const io_user_scalar_t * input,mach_msg_type_number_t inputCount,io_struct_inband_t output,IOByteCount * outputCount)5405 shim_io_connect_method_scalarI_structureO(
5406 
5407 	IOExternalMethod *      method,
5408 	IOService *             object,
5409 	const io_user_scalar_t * input,
5410 	mach_msg_type_number_t  inputCount,
5411 	io_struct_inband_t              output,
5412 	IOByteCount *   outputCount )
5413 {
5414 	IOMethod            func;
5415 	IOReturn            err;
5416 
5417 	err = kIOReturnBadArgument;
5418 
5419 	do {
5420 		if (inputCount != method->count0) {
5421 			IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0);
5422 			DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0);
5423 			continue;
5424 		}
5425 		if ((kIOUCVariableStructureSize != method->count1)
5426 		    && (*outputCount != method->count1)) {
5427 			IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)*outputCount, (uint64_t)method->count1, (uint64_t)kIOUCVariableStructureSize);
5428 			DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)*outputCount, uint64_t, (uint64_t)method->count1);
5429 			continue;
5430 		}
5431 
5432 		func = method->func;
5433 
5434 		switch (inputCount) {
5435 		case 5:
5436 			err = (object->*func)(  ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5437 			    ARG32(input[3]), ARG32(input[4]),
5438 			    output );
5439 			break;
5440 		case 4:
5441 			err = (object->*func)(  ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5442 			    ARG32(input[3]),
5443 			    output, (void *)outputCount );
5444 			break;
5445 		case 3:
5446 			err = (object->*func)(  ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5447 			    output, (void *)outputCount, NULL );
5448 			break;
5449 		case 2:
5450 			err = (object->*func)(  ARG32(input[0]), ARG32(input[1]),
5451 			    output, (void *)outputCount, NULL, NULL );
5452 			break;
5453 		case 1:
5454 			err = (object->*func)(  ARG32(input[0]),
5455 			    output, (void *)outputCount, NULL, NULL, NULL );
5456 			break;
5457 		case 0:
5458 			err = (object->*func)(  output, (void *)outputCount, NULL, NULL, NULL, NULL );
5459 			break;
5460 
5461 		default:
5462 			IOLog("%s: Bad method table\n", object->getName());
5463 		}
5464 	}while (false);
5465 
5466 	return err;
5467 }
5468 
5469 
5470 kern_return_t
shim_io_async_method_scalarI_structureO(IOExternalAsyncMethod * method,IOService * object,mach_port_t asyncWakePort,io_user_reference_t * asyncReference,uint32_t asyncReferenceCount,const io_user_scalar_t * input,mach_msg_type_number_t inputCount,io_struct_inband_t output,mach_msg_type_number_t * outputCount)5471 shim_io_async_method_scalarI_structureO(
5472 	IOExternalAsyncMethod * method,
5473 	IOService *             object,
5474 	mach_port_t             asyncWakePort,
5475 	io_user_reference_t *   asyncReference,
5476 	uint32_t                asyncReferenceCount,
5477 	const io_user_scalar_t * input,
5478 	mach_msg_type_number_t  inputCount,
5479 	io_struct_inband_t              output,
5480 	mach_msg_type_number_t *        outputCount )
5481 {
5482 	IOAsyncMethod       func;
5483 	uint32_t            i;
5484 	IOReturn            err;
5485 	io_async_ref_t      reference;
5486 
5487 	for (i = 0; i < asyncReferenceCount; i++) {
5488 		reference[i] = REF32(asyncReference[i]);
5489 	}
5490 
5491 	err = kIOReturnBadArgument;
5492 	do {
5493 		if (inputCount != method->count0) {
5494 			IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0);
5495 			DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0);
5496 			continue;
5497 		}
5498 		if ((kIOUCVariableStructureSize != method->count1)
5499 		    && (*outputCount != method->count1)) {
5500 			IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)*outputCount, (uint64_t)method->count1, (uint64_t)kIOUCVariableStructureSize);
5501 			DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)*outputCount, uint64_t, (uint64_t)method->count1);
5502 			continue;
5503 		}
5504 
5505 		func = method->func;
5506 
5507 		switch (inputCount) {
5508 		case 5:
5509 			err = (object->*func)(  reference,
5510 			    ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5511 			    ARG32(input[3]), ARG32(input[4]),
5512 			    output );
5513 			break;
5514 		case 4:
5515 			err = (object->*func)(  reference,
5516 			    ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5517 			    ARG32(input[3]),
5518 			    output, (void *)outputCount );
5519 			break;
5520 		case 3:
5521 			err = (object->*func)(  reference,
5522 			    ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5523 			    output, (void *)outputCount, NULL );
5524 			break;
5525 		case 2:
5526 			err = (object->*func)(  reference,
5527 			    ARG32(input[0]), ARG32(input[1]),
5528 			    output, (void *)outputCount, NULL, NULL );
5529 			break;
5530 		case 1:
5531 			err = (object->*func)(  reference,
5532 			    ARG32(input[0]),
5533 			    output, (void *)outputCount, NULL, NULL, NULL );
5534 			break;
5535 		case 0:
5536 			err = (object->*func)(  reference,
5537 			    output, (void *)outputCount, NULL, NULL, NULL, NULL );
5538 			break;
5539 
5540 		default:
5541 			IOLog("%s: Bad method table\n", object->getName());
5542 		}
5543 	}while (false);
5544 
5545 	return err;
5546 }
5547 
5548 /* Routine io_connect_method_scalarI_structureI */
5549 kern_return_t
is_io_connect_method_scalarI_structureI(io_connect_t connect,uint32_t index,io_scalar_inband_t input,mach_msg_type_number_t inputCount,io_struct_inband_t inputStruct,mach_msg_type_number_t inputStructCount)5550 is_io_connect_method_scalarI_structureI(
5551 	io_connect_t            connect,
5552 	uint32_t                index,
5553 	io_scalar_inband_t      input,
5554 	mach_msg_type_number_t  inputCount,
5555 	io_struct_inband_t      inputStruct,
5556 	mach_msg_type_number_t  inputStructCount )
5557 {
5558 	uint32_t i;
5559 	io_scalar_inband64_t _input;
5560 
5561 	mach_msg_type_number_t scalar_outputCnt = 0;
5562 	mach_msg_type_number_t inband_outputCnt = 0;
5563 	mach_vm_size_t ool_output_size = 0;
5564 
5565 	for (i = 0; i < inputCount; i++) {
5566 		_input[i] = SCALAR64(input[i]);
5567 	}
5568 
5569 	return is_io_connect_method(connect, index,
5570 	           _input, inputCount,
5571 	           inputStruct, inputStructCount,
5572 	           0, 0,
5573 	           NULL, &inband_outputCnt,
5574 	           NULL, &scalar_outputCnt,
5575 	           0, &ool_output_size);
5576 }
5577 
5578 kern_return_t
shim_io_connect_method_scalarI_structureI(IOExternalMethod * method,IOService * object,const io_user_scalar_t * input,mach_msg_type_number_t inputCount,io_struct_inband_t inputStruct,mach_msg_type_number_t inputStructCount)5579 shim_io_connect_method_scalarI_structureI(
5580 	IOExternalMethod *  method,
5581 	IOService *         object,
5582 	const io_user_scalar_t * input,
5583 	mach_msg_type_number_t  inputCount,
5584 	io_struct_inband_t              inputStruct,
5585 	mach_msg_type_number_t  inputStructCount )
5586 {
5587 	IOMethod            func;
5588 	IOReturn            err = kIOReturnBadArgument;
5589 
5590 	do{
5591 		if (inputCount != method->count0) {
5592 			IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0);
5593 			DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0);
5594 			continue;
5595 		}
5596 		if ((kIOUCVariableStructureSize != method->count1)
5597 		    && (inputStructCount != method->count1)) {
5598 			IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputStructCount, (uint64_t)method->count1, (uint64_t)kIOUCVariableStructureSize);
5599 			DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputStructCount, uint64_t, (uint64_t)method->count1);
5600 			continue;
5601 		}
5602 
5603 		func = method->func;
5604 
5605 		switch (inputCount) {
5606 		case 5:
5607 			err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5608 			    ARG32(input[3]), ARG32(input[4]),
5609 			    inputStruct );
5610 			break;
5611 		case 4:
5612 			err = (object->*func)( ARG32(input[0]), ARG32(input[1]), (void *)  input[2],
5613 			    ARG32(input[3]),
5614 			    inputStruct, (void *)(uintptr_t)inputStructCount );
5615 			break;
5616 		case 3:
5617 			err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5618 			    inputStruct, (void *)(uintptr_t)inputStructCount,
5619 			    NULL );
5620 			break;
5621 		case 2:
5622 			err = (object->*func)( ARG32(input[0]), ARG32(input[1]),
5623 			    inputStruct, (void *)(uintptr_t)inputStructCount,
5624 			    NULL, NULL );
5625 			break;
5626 		case 1:
5627 			err = (object->*func)( ARG32(input[0]),
5628 			    inputStruct, (void *)(uintptr_t)inputStructCount,
5629 			    NULL, NULL, NULL );
5630 			break;
5631 		case 0:
5632 			err = (object->*func)( inputStruct, (void *)(uintptr_t)inputStructCount,
5633 			    NULL, NULL, NULL, NULL );
5634 			break;
5635 
5636 		default:
5637 			IOLog("%s: Bad method table\n", object->getName());
5638 		}
5639 	}while (false);
5640 
5641 	return err;
5642 }
5643 
5644 kern_return_t
shim_io_async_method_scalarI_structureI(IOExternalAsyncMethod * method,IOService * object,mach_port_t asyncWakePort,io_user_reference_t * asyncReference,uint32_t asyncReferenceCount,const io_user_scalar_t * input,mach_msg_type_number_t inputCount,io_struct_inband_t inputStruct,mach_msg_type_number_t inputStructCount)5645 shim_io_async_method_scalarI_structureI(
5646 	IOExternalAsyncMethod * method,
5647 	IOService *             object,
5648 	mach_port_t             asyncWakePort,
5649 	io_user_reference_t *   asyncReference,
5650 	uint32_t                asyncReferenceCount,
5651 	const io_user_scalar_t * input,
5652 	mach_msg_type_number_t  inputCount,
5653 	io_struct_inband_t              inputStruct,
5654 	mach_msg_type_number_t  inputStructCount )
5655 {
5656 	IOAsyncMethod       func;
5657 	uint32_t            i;
5658 	IOReturn            err = kIOReturnBadArgument;
5659 	io_async_ref_t      reference;
5660 
5661 	for (i = 0; i < asyncReferenceCount; i++) {
5662 		reference[i] = REF32(asyncReference[i]);
5663 	}
5664 
5665 	do{
5666 		if (inputCount != method->count0) {
5667 			IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0);
5668 			DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0);
5669 			continue;
5670 		}
5671 		if ((kIOUCVariableStructureSize != method->count1)
5672 		    && (inputStructCount != method->count1)) {
5673 			IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputStructCount, (uint64_t)method->count1, (uint64_t)kIOUCVariableStructureSize);
5674 			DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputStructCount, uint64_t, (uint64_t)method->count1);
5675 			continue;
5676 		}
5677 
5678 		func = method->func;
5679 
5680 		switch (inputCount) {
5681 		case 5:
5682 			err = (object->*func)(  reference,
5683 			    ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5684 			    ARG32(input[3]), ARG32(input[4]),
5685 			    inputStruct );
5686 			break;
5687 		case 4:
5688 			err = (object->*func)(  reference,
5689 			    ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5690 			    ARG32(input[3]),
5691 			    inputStruct, (void *)(uintptr_t)inputStructCount );
5692 			break;
5693 		case 3:
5694 			err = (object->*func)(  reference,
5695 			    ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5696 			    inputStruct, (void *)(uintptr_t)inputStructCount,
5697 			    NULL );
5698 			break;
5699 		case 2:
5700 			err = (object->*func)(  reference,
5701 			    ARG32(input[0]), ARG32(input[1]),
5702 			    inputStruct, (void *)(uintptr_t)inputStructCount,
5703 			    NULL, NULL );
5704 			break;
5705 		case 1:
5706 			err = (object->*func)(  reference,
5707 			    ARG32(input[0]),
5708 			    inputStruct, (void *)(uintptr_t)inputStructCount,
5709 			    NULL, NULL, NULL );
5710 			break;
5711 		case 0:
5712 			err = (object->*func)(  reference,
5713 			    inputStruct, (void *)(uintptr_t)inputStructCount,
5714 			    NULL, NULL, NULL, NULL );
5715 			break;
5716 
5717 		default:
5718 			IOLog("%s: Bad method table\n", object->getName());
5719 		}
5720 	}while (false);
5721 
5722 	return err;
5723 }
5724 
5725 /* Routine io_connect_method_structureI_structureO */
5726 kern_return_t
is_io_connect_method_structureI_structureO(io_object_t connect,uint32_t index,io_struct_inband_t input,mach_msg_type_number_t inputCount,io_struct_inband_t output,mach_msg_type_number_t * outputCount)5727 is_io_connect_method_structureI_structureO(
5728 	io_object_t     connect,
5729 	uint32_t        index,
5730 	io_struct_inband_t              input,
5731 	mach_msg_type_number_t  inputCount,
5732 	io_struct_inband_t              output,
5733 	mach_msg_type_number_t *        outputCount )
5734 {
5735 	mach_msg_type_number_t scalar_outputCnt = 0;
5736 	mach_vm_size_t ool_output_size = 0;
5737 
5738 	return is_io_connect_method(connect, index,
5739 	           NULL, 0,
5740 	           input, inputCount,
5741 	           0, 0,
5742 	           output, outputCount,
5743 	           NULL, &scalar_outputCnt,
5744 	           0, &ool_output_size);
5745 }
5746 
5747 kern_return_t
shim_io_connect_method_structureI_structureO(IOExternalMethod * method,IOService * object,io_struct_inband_t input,mach_msg_type_number_t inputCount,io_struct_inband_t output,IOByteCount * outputCount)5748 shim_io_connect_method_structureI_structureO(
5749 	IOExternalMethod *  method,
5750 	IOService *         object,
5751 	io_struct_inband_t              input,
5752 	mach_msg_type_number_t  inputCount,
5753 	io_struct_inband_t              output,
5754 	IOByteCount *   outputCount )
5755 {
5756 	IOMethod            func;
5757 	IOReturn            err = kIOReturnBadArgument;
5758 
5759 	do{
5760 		if ((kIOUCVariableStructureSize != method->count0)
5761 		    && (inputCount != method->count0)) {
5762 			IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0, (uint64_t)kIOUCVariableStructureSize);
5763 			DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0);
5764 			continue;
5765 		}
5766 		if ((kIOUCVariableStructureSize != method->count1)
5767 		    && (*outputCount != method->count1)) {
5768 			IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)*outputCount, (uint64_t)method->count1, (uint64_t)kIOUCVariableStructureSize);
5769 			DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)*outputCount, uint64_t, (uint64_t)method->count1);
5770 			continue;
5771 		}
5772 
5773 		func = method->func;
5774 
5775 		if (method->count1) {
5776 			if (method->count0) {
5777 				err = (object->*func)( input, output,
5778 				    (void *)(uintptr_t)inputCount, outputCount, NULL, NULL );
5779 			} else {
5780 				err = (object->*func)( output, outputCount, NULL, NULL, NULL, NULL );
5781 			}
5782 		} else {
5783 			err = (object->*func)( input, (void *)(uintptr_t)inputCount, NULL, NULL, NULL, NULL );
5784 		}
5785 	}while (false);
5786 
5787 
5788 	return err;
5789 }
5790 
5791 kern_return_t
shim_io_async_method_structureI_structureO(IOExternalAsyncMethod * method,IOService * object,mach_port_t asyncWakePort,io_user_reference_t * asyncReference,uint32_t asyncReferenceCount,io_struct_inband_t input,mach_msg_type_number_t inputCount,io_struct_inband_t output,mach_msg_type_number_t * outputCount)5792 shim_io_async_method_structureI_structureO(
5793 	IOExternalAsyncMethod * method,
5794 	IOService *             object,
5795 	mach_port_t           asyncWakePort,
5796 	io_user_reference_t * asyncReference,
5797 	uint32_t              asyncReferenceCount,
5798 	io_struct_inband_t              input,
5799 	mach_msg_type_number_t  inputCount,
5800 	io_struct_inband_t              output,
5801 	mach_msg_type_number_t *        outputCount )
5802 {
5803 	IOAsyncMethod       func;
5804 	uint32_t            i;
5805 	IOReturn            err;
5806 	io_async_ref_t      reference;
5807 
5808 	for (i = 0; i < asyncReferenceCount; i++) {
5809 		reference[i] = REF32(asyncReference[i]);
5810 	}
5811 
5812 	err = kIOReturnBadArgument;
5813 	do{
5814 		if ((kIOUCVariableStructureSize != method->count0)
5815 		    && (inputCount != method->count0)) {
5816 			IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0, (uint64_t)kIOUCVariableStructureSize);
5817 			DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0);
5818 			continue;
5819 		}
5820 		if ((kIOUCVariableStructureSize != method->count1)
5821 		    && (*outputCount != method->count1)) {
5822 			IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)*outputCount, (uint64_t)method->count1, (uint64_t)kIOUCVariableStructureSize);
5823 			DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)*outputCount, uint64_t, (uint64_t)method->count1);
5824 			continue;
5825 		}
5826 
5827 		func = method->func;
5828 
5829 		if (method->count1) {
5830 			if (method->count0) {
5831 				err = (object->*func)( reference,
5832 				    input, output,
5833 				    (void *)(uintptr_t)inputCount, outputCount, NULL, NULL );
5834 			} else {
5835 				err = (object->*func)( reference,
5836 				    output, outputCount, NULL, NULL, NULL, NULL );
5837 			}
5838 		} else {
5839 			err = (object->*func)( reference,
5840 			    input, (void *)(uintptr_t)inputCount, NULL, NULL, NULL, NULL );
5841 		}
5842 	}while (false);
5843 
5844 	return err;
5845 }
5846 
5847 /* Routine io_catalog_send_data */
5848 kern_return_t
is_io_catalog_send_data(mach_port_t master_port,uint32_t flag,io_buf_ptr_t inData,mach_msg_type_number_t inDataCount,kern_return_t * result)5849 is_io_catalog_send_data(
5850 	mach_port_t             master_port,
5851 	uint32_t                flag,
5852 	io_buf_ptr_t            inData,
5853 	mach_msg_type_number_t  inDataCount,
5854 	kern_return_t *         result)
5855 {
5856 	// Allow sending catalog data if there is no kextd and the kernel is DEVELOPMENT || DEBUG
5857 #if NO_KEXTD && !(DEVELOPMENT || DEBUG)
5858 	return kIOReturnNotPrivileged;
5859 #else /* NO_KEXTD && !(DEVELOPMENT || DEBUG) */
5860 	OSObject * obj = NULL;
5861 	vm_offset_t data;
5862 	kern_return_t kr = kIOReturnError;
5863 
5864 	//printf("io_catalog_send_data called. flag: %d\n", flag);
5865 
5866 	if (master_port != master_device_port) {
5867 		return kIOReturnNotPrivileged;
5868 	}
5869 
5870 	if ((flag != kIOCatalogRemoveKernelLinker__Removed &&
5871 	    flag != kIOCatalogKextdActive &&
5872 	    flag != kIOCatalogKextdFinishedLaunching) &&
5873 	    (!inData || !inDataCount)) {
5874 		return kIOReturnBadArgument;
5875 	}
5876 
5877 	if (!IOCurrentTaskHasEntitlement(kIOCatalogManagementEntitlement)) {
5878 		OSString * taskName = IOCopyLogNameForPID(proc_selfpid());
5879 		IOLog("IOCatalogueSendData(%s): Not entitled\n", taskName ? taskName->getCStringNoCopy() : "");
5880 		OSSafeReleaseNULL(taskName);
5881 		// For now, fake success to not break applications relying on this function succeeding.
5882 		// See <rdar://problem/32554970> for more details.
5883 		return kIOReturnSuccess;
5884 	}
5885 
5886 	if (inData) {
5887 		vm_map_offset_t map_data;
5888 
5889 		if (inDataCount > sizeof(io_struct_inband_t) * 1024) {
5890 			return kIOReturnMessageTooLarge;
5891 		}
5892 
5893 		kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t)inData);
5894 		data = CAST_DOWN(vm_offset_t, map_data);
5895 
5896 		if (kr != KERN_SUCCESS) {
5897 			return kr;
5898 		}
5899 
5900 		// must return success after vm_map_copyout() succeeds
5901 
5902 		if (inDataCount) {
5903 			obj = (OSObject *)OSUnserializeXML((const char *)data, inDataCount);
5904 			vm_deallocate( kernel_map, data, inDataCount );
5905 			if (!obj) {
5906 				*result = kIOReturnNoMemory;
5907 				return KERN_SUCCESS;
5908 			}
5909 		}
5910 	}
5911 
5912 	switch (flag) {
5913 	case kIOCatalogResetDrivers:
5914 	case kIOCatalogResetDriversNoMatch: {
5915 		OSArray * array;
5916 
5917 		array = OSDynamicCast(OSArray, obj);
5918 		if (array) {
5919 			if (!gIOCatalogue->resetAndAddDrivers(array,
5920 			    flag == kIOCatalogResetDrivers)) {
5921 				kr = kIOReturnError;
5922 			}
5923 		} else {
5924 			kr = kIOReturnBadArgument;
5925 		}
5926 	}
5927 	break;
5928 
5929 	case kIOCatalogAddDrivers:
5930 	case kIOCatalogAddDriversNoMatch: {
5931 		OSArray * array;
5932 
5933 		array = OSDynamicCast(OSArray, obj);
5934 		if (array) {
5935 			if (!gIOCatalogue->addDrivers( array,
5936 			    flag == kIOCatalogAddDrivers)) {
5937 				kr = kIOReturnError;
5938 			}
5939 		} else {
5940 			kr = kIOReturnBadArgument;
5941 		}
5942 	}
5943 	break;
5944 
5945 	case kIOCatalogRemoveDrivers:
5946 	case kIOCatalogRemoveDriversNoMatch: {
5947 		OSDictionary * dict;
5948 
5949 		dict = OSDynamicCast(OSDictionary, obj);
5950 		if (dict) {
5951 			if (!gIOCatalogue->removeDrivers( dict,
5952 			    flag == kIOCatalogRemoveDrivers )) {
5953 				kr = kIOReturnError;
5954 			}
5955 		} else {
5956 			kr = kIOReturnBadArgument;
5957 		}
5958 	}
5959 	break;
5960 
5961 	case kIOCatalogStartMatching__Removed:
5962 	case kIOCatalogRemoveKernelLinker__Removed:
5963 	case kIOCatalogKextdActive:
5964 	case kIOCatalogKextdFinishedLaunching:
5965 		kr = KERN_NOT_SUPPORTED;
5966 		break;
5967 
5968 	default:
5969 		kr = kIOReturnBadArgument;
5970 		break;
5971 	}
5972 
5973 	if (obj) {
5974 		obj->release();
5975 	}
5976 
5977 	*result = kr;
5978 	return KERN_SUCCESS;
5979 #endif /* NO_KEXTD && !(DEVELOPMENT || DEBUG) */
5980 }
5981 
5982 /* Routine io_catalog_terminate */
5983 kern_return_t
is_io_catalog_terminate(mach_port_t master_port,uint32_t flag,io_name_t name)5984 is_io_catalog_terminate(
5985 	mach_port_t master_port,
5986 	uint32_t flag,
5987 	io_name_t name )
5988 {
5989 	kern_return_t          kr;
5990 
5991 	if (master_port != master_device_port) {
5992 		return kIOReturnNotPrivileged;
5993 	}
5994 
5995 	kr = IOUserClient::clientHasPrivilege((void *) current_task(),
5996 	    kIOClientPrivilegeAdministrator );
5997 	if (kIOReturnSuccess != kr) {
5998 		return kr;
5999 	}
6000 
6001 	switch (flag) {
6002 #if !defined(SECURE_KERNEL)
6003 	case kIOCatalogServiceTerminate:
6004 		kr = gIOCatalogue->terminateDrivers(NULL, name);
6005 		break;
6006 
6007 	case kIOCatalogModuleUnload:
6008 	case kIOCatalogModuleTerminate:
6009 		kr = gIOCatalogue->terminateDriversForModule(name,
6010 		    flag == kIOCatalogModuleUnload);
6011 		break;
6012 #endif
6013 
6014 	default:
6015 		kr = kIOReturnBadArgument;
6016 		break;
6017 	}
6018 
6019 	return kr;
6020 }
6021 
6022 /* Routine io_catalog_get_data */
6023 kern_return_t
is_io_catalog_get_data(mach_port_t master_port,uint32_t flag,io_buf_ptr_t * outData,mach_msg_type_number_t * outDataCount)6024 is_io_catalog_get_data(
6025 	mach_port_t             master_port,
6026 	uint32_t                flag,
6027 	io_buf_ptr_t            *outData,
6028 	mach_msg_type_number_t  *outDataCount)
6029 {
6030 	kern_return_t kr = kIOReturnSuccess;
6031 	OSSerialize * s;
6032 
6033 	if (master_port != master_device_port) {
6034 		return kIOReturnNotPrivileged;
6035 	}
6036 
6037 	//printf("io_catalog_get_data called. flag: %d\n", flag);
6038 
6039 	s = OSSerialize::withCapacity(4096);
6040 	if (!s) {
6041 		return kIOReturnNoMemory;
6042 	}
6043 
6044 	kr = gIOCatalogue->serializeData(flag, s);
6045 
6046 	if (kr == kIOReturnSuccess) {
6047 		mach_vm_address_t data;
6048 		vm_map_copy_t copy;
6049 		unsigned int size;
6050 
6051 		size = s->getLength();
6052 		kr = mach_vm_allocate_kernel(kernel_map, &data, size, VM_FLAGS_ANYWHERE, VM_KERN_MEMORY_IOKIT);
6053 		if (kr == kIOReturnSuccess) {
6054 			bcopy(s->text(), (void *)data, size);
6055 			kr = vm_map_copyin(kernel_map, data, size, true, &copy);
6056 			*outData = (char *)copy;
6057 			*outDataCount = size;
6058 		}
6059 	}
6060 
6061 	s->release();
6062 
6063 	return kr;
6064 }
6065 
6066 /* Routine io_catalog_get_gen_count */
6067 kern_return_t
is_io_catalog_get_gen_count(mach_port_t master_port,uint32_t * genCount)6068 is_io_catalog_get_gen_count(
6069 	mach_port_t             master_port,
6070 	uint32_t                *genCount)
6071 {
6072 	if (master_port != master_device_port) {
6073 		return kIOReturnNotPrivileged;
6074 	}
6075 
6076 	//printf("io_catalog_get_gen_count called.\n");
6077 
6078 	if (!genCount) {
6079 		return kIOReturnBadArgument;
6080 	}
6081 
6082 	*genCount = gIOCatalogue->getGenerationCount();
6083 
6084 	return kIOReturnSuccess;
6085 }
6086 
6087 /* Routine io_catalog_module_loaded.
6088  * Is invoked from IOKitLib's IOCatalogueModuleLoaded(). Doesn't seem to be used.
6089  */
6090 kern_return_t
is_io_catalog_module_loaded(mach_port_t master_port,io_name_t name)6091 is_io_catalog_module_loaded(
6092 	mach_port_t             master_port,
6093 	io_name_t               name)
6094 {
6095 	if (master_port != master_device_port) {
6096 		return kIOReturnNotPrivileged;
6097 	}
6098 
6099 	//printf("io_catalog_module_loaded called. name %s\n", name);
6100 
6101 	if (!name) {
6102 		return kIOReturnBadArgument;
6103 	}
6104 
6105 	gIOCatalogue->moduleHasLoaded(name);
6106 
6107 	return kIOReturnSuccess;
6108 }
6109 
6110 kern_return_t
is_io_catalog_reset(mach_port_t master_port,uint32_t flag)6111 is_io_catalog_reset(
6112 	mach_port_t             master_port,
6113 	uint32_t                flag)
6114 {
6115 	if (master_port != master_device_port) {
6116 		return kIOReturnNotPrivileged;
6117 	}
6118 
6119 	switch (flag) {
6120 	case kIOCatalogResetDefault:
6121 		gIOCatalogue->reset();
6122 		break;
6123 
6124 	default:
6125 		return kIOReturnBadArgument;
6126 	}
6127 
6128 	return kIOReturnSuccess;
6129 }
6130 
6131 kern_return_t
iokit_user_client_trap(struct iokit_user_client_trap_args * args)6132 iokit_user_client_trap(struct iokit_user_client_trap_args *args)
6133 {
6134 	kern_return_t    result = kIOReturnBadArgument;
6135 	IOUserClient   * userClient;
6136 	OSObject       * object;
6137 	uintptr_t        ref;
6138 	mach_port_name_t portName;
6139 
6140 	ref     = (uintptr_t) args->userClientRef;
6141 
6142 	if ((ref == MACH_PORT_DEAD) || (ref == (uintptr_t) MACH_PORT_NULL)) {
6143 		return kIOReturnBadArgument;
6144 	}
6145 	// kobject port names always have b0-1 set, so we use these bits as flags to
6146 	// iokit_user_client_trap()
6147 	// keep this up to date with ipc_entry_name_mask();
6148 	portName = (mach_port_name_t) (ref | 3);
6149 	if (((1ULL << 32) & ref) || !(1 & ref)) {
6150 		object = iokit_lookup_uext_ref_current_task(portName);
6151 		if (object) {
6152 			result = IOUserServerUEXTTrap(object, args->p1, args->p2, args->p3, args->p4, args->p5, args->p6);
6153 		}
6154 		OSSafeReleaseNULL(object);
6155 	} else {
6156 		io_object_t ref_current_task = iokit_lookup_connect_ref_current_task((mach_port_name_t) ref);
6157 		if ((userClient = OSDynamicCast(IOUserClient, ref_current_task))) {
6158 			IOExternalTrap *trap = NULL;
6159 			IOService *target = NULL;
6160 
6161 			result = kIOReturnSuccess;
6162 			io_filter_policy_t filterPolicy = userClient->filterForTask(current_task(), 0);
6163 			if (filterPolicy && gIOUCFilterCallbacks->io_filter_applier) {
6164 				result = gIOUCFilterCallbacks->io_filter_applier(userClient, filterPolicy, io_filter_type_trap, args->index);
6165 			}
6166 			if (kIOReturnSuccess == result) {
6167 				trap = userClient->getTargetAndTrapForIndex(&target, args->index);
6168 			}
6169 			if (trap && target) {
6170 				IOTrap func;
6171 
6172 				func = trap->func;
6173 
6174 				if (func) {
6175 					result = (target->*func)(args->p1, args->p2, args->p3, args->p4, args->p5, args->p6);
6176 				}
6177 			}
6178 
6179 			iokit_remove_connect_reference(userClient);
6180 		} else {
6181 			OSSafeReleaseNULL(ref_current_task);
6182 		}
6183 	}
6184 
6185 	return result;
6186 }
6187 
6188 /* Routine io_device_tree_entry_exists_with_name */
6189 kern_return_t
is_io_device_tree_entry_exists_with_name(mach_port_t master_port,io_name_t name,boolean_t * exists)6190 is_io_device_tree_entry_exists_with_name(
6191 	mach_port_t master_port,
6192 	io_name_t name,
6193 	boolean_t *exists )
6194 {
6195 	OSCollectionIterator *iter;
6196 
6197 	if (master_port != master_device_port) {
6198 		return kIOReturnNotPrivileged;
6199 	}
6200 
6201 	iter = IODTFindMatchingEntries(IORegistryEntry::getRegistryRoot(), kIODTRecursive, name);
6202 	*exists = iter && iter->getNextObject();
6203 	OSSafeReleaseNULL(iter);
6204 
6205 	return kIOReturnSuccess;
6206 }
6207 } /* extern "C" */
6208 
6209 IOReturn
externalMethod(uint32_t selector,IOExternalMethodArguments * args,IOExternalMethodDispatch * dispatch,OSObject * target,void * reference)6210 IOUserClient::externalMethod( uint32_t selector, IOExternalMethodArguments * args,
6211     IOExternalMethodDispatch * dispatch, OSObject * target, void * reference )
6212 {
6213 	IOReturn    err;
6214 	IOService * object;
6215 	IOByteCount structureOutputSize;
6216 
6217 	if (dispatch) {
6218 		uint32_t count;
6219 		count = dispatch->checkScalarInputCount;
6220 		if ((kIOUCVariableStructureSize != count) && (count != args->scalarInputCount)) {
6221 			return kIOReturnBadArgument;
6222 		}
6223 
6224 		count = dispatch->checkStructureInputSize;
6225 		if ((kIOUCVariableStructureSize != count)
6226 		    && (count != ((args->structureInputDescriptor)
6227 		    ? args->structureInputDescriptor->getLength() : args->structureInputSize))) {
6228 			return kIOReturnBadArgument;
6229 		}
6230 
6231 		count = dispatch->checkScalarOutputCount;
6232 		if ((kIOUCVariableStructureSize != count) && (count != args->scalarOutputCount)) {
6233 			return kIOReturnBadArgument;
6234 		}
6235 
6236 		count = dispatch->checkStructureOutputSize;
6237 		if ((kIOUCVariableStructureSize != count)
6238 		    && (count != ((args->structureOutputDescriptor)
6239 		    ? args->structureOutputDescriptor->getLength() : args->structureOutputSize))) {
6240 			return kIOReturnBadArgument;
6241 		}
6242 
6243 		if (dispatch->function) {
6244 			err = (*dispatch->function)(target, reference, args);
6245 		} else {
6246 			err = kIOReturnNoCompletion; /* implementator can dispatch */
6247 		}
6248 		return err;
6249 	}
6250 
6251 
6252 	// pre-Leopard API's don't do ool structs
6253 	if (args->structureInputDescriptor || args->structureOutputDescriptor) {
6254 		err = kIOReturnIPCError;
6255 		return err;
6256 	}
6257 
6258 	structureOutputSize = args->structureOutputSize;
6259 
6260 	if (args->asyncWakePort) {
6261 		IOExternalAsyncMethod * method;
6262 		object = NULL;
6263 		if (!(method = getAsyncTargetAndMethodForIndex(&object, selector)) || !object) {
6264 			return kIOReturnUnsupported;
6265 		}
6266 
6267 		if (kIOUCForegroundOnly & method->flags) {
6268 			if (task_is_gpu_denied(current_task())) {
6269 				return kIOReturnNotPermitted;
6270 			}
6271 		}
6272 
6273 		switch (method->flags & kIOUCTypeMask) {
6274 		case kIOUCScalarIStructI:
6275 			err = shim_io_async_method_scalarI_structureI( method, object,
6276 			    args->asyncWakePort, args->asyncReference, args->asyncReferenceCount,
6277 			    args->scalarInput, args->scalarInputCount,
6278 			    (char *)args->structureInput, args->structureInputSize );
6279 			break;
6280 
6281 		case kIOUCScalarIScalarO:
6282 			err = shim_io_async_method_scalarI_scalarO( method, object,
6283 			    args->asyncWakePort, args->asyncReference, args->asyncReferenceCount,
6284 			    args->scalarInput, args->scalarInputCount,
6285 			    args->scalarOutput, &args->scalarOutputCount );
6286 			break;
6287 
6288 		case kIOUCScalarIStructO:
6289 			err = shim_io_async_method_scalarI_structureO( method, object,
6290 			    args->asyncWakePort, args->asyncReference, args->asyncReferenceCount,
6291 			    args->scalarInput, args->scalarInputCount,
6292 			    (char *) args->structureOutput, &args->structureOutputSize );
6293 			break;
6294 
6295 
6296 		case kIOUCStructIStructO:
6297 			err = shim_io_async_method_structureI_structureO( method, object,
6298 			    args->asyncWakePort, args->asyncReference, args->asyncReferenceCount,
6299 			    (char *)args->structureInput, args->structureInputSize,
6300 			    (char *) args->structureOutput, &args->structureOutputSize );
6301 			break;
6302 
6303 		default:
6304 			err = kIOReturnBadArgument;
6305 			break;
6306 		}
6307 	} else {
6308 		IOExternalMethod *      method;
6309 		object = NULL;
6310 		if (!(method = getTargetAndMethodForIndex(&object, selector)) || !object) {
6311 			return kIOReturnUnsupported;
6312 		}
6313 
6314 		if (kIOUCForegroundOnly & method->flags) {
6315 			if (task_is_gpu_denied(current_task())) {
6316 				return kIOReturnNotPermitted;
6317 			}
6318 		}
6319 
6320 		switch (method->flags & kIOUCTypeMask) {
6321 		case kIOUCScalarIStructI:
6322 			err = shim_io_connect_method_scalarI_structureI( method, object,
6323 			    args->scalarInput, args->scalarInputCount,
6324 			    (char *) args->structureInput, args->structureInputSize );
6325 			break;
6326 
6327 		case kIOUCScalarIScalarO:
6328 			err = shim_io_connect_method_scalarI_scalarO( method, object,
6329 			    args->scalarInput, args->scalarInputCount,
6330 			    args->scalarOutput, &args->scalarOutputCount );
6331 			break;
6332 
6333 		case kIOUCScalarIStructO:
6334 			err = shim_io_connect_method_scalarI_structureO( method, object,
6335 			    args->scalarInput, args->scalarInputCount,
6336 			    (char *) args->structureOutput, &structureOutputSize );
6337 			break;
6338 
6339 
6340 		case kIOUCStructIStructO:
6341 			err = shim_io_connect_method_structureI_structureO( method, object,
6342 			    (char *) args->structureInput, args->structureInputSize,
6343 			    (char *) args->structureOutput, &structureOutputSize );
6344 			break;
6345 
6346 		default:
6347 			err = kIOReturnBadArgument;
6348 			break;
6349 		}
6350 	}
6351 
6352 	if (structureOutputSize > UINT_MAX) {
6353 		structureOutputSize = 0;
6354 		err = kIOReturnBadArgument;
6355 	}
6356 
6357 	args->structureOutputSize = ((typeof(args->structureOutputSize))structureOutputSize);
6358 
6359 	return err;
6360 }
6361 
6362 IOReturn
registerFilterCallbacks(const struct io_filter_callbacks * callbacks,size_t size)6363 IOUserClient::registerFilterCallbacks(const struct io_filter_callbacks *callbacks, size_t size)
6364 {
6365 	if (size < sizeof(*callbacks)) {
6366 		return kIOReturnBadArgument;
6367 	}
6368 	if (!OSCompareAndSwapPtr(NULL, __DECONST(void *, callbacks), &gIOUCFilterCallbacks)) {
6369 		return kIOReturnBusy;
6370 	}
6371 	return kIOReturnSuccess;
6372 }
6373 
6374 #if __LP64__
6375 OSMetaClassDefineReservedUnused(IOUserClient, 0);
6376 OSMetaClassDefineReservedUnused(IOUserClient, 1);
6377 #else
6378 OSMetaClassDefineReservedUsed(IOUserClient, 0);
6379 OSMetaClassDefineReservedUsed(IOUserClient, 1);
6380 #endif
6381 OSMetaClassDefineReservedUnused(IOUserClient, 2);
6382 OSMetaClassDefineReservedUnused(IOUserClient, 3);
6383 OSMetaClassDefineReservedUnused(IOUserClient, 4);
6384 OSMetaClassDefineReservedUnused(IOUserClient, 5);
6385 OSMetaClassDefineReservedUnused(IOUserClient, 6);
6386 OSMetaClassDefineReservedUnused(IOUserClient, 7);
6387 OSMetaClassDefineReservedUnused(IOUserClient, 8);
6388 OSMetaClassDefineReservedUnused(IOUserClient, 9);
6389 OSMetaClassDefineReservedUnused(IOUserClient, 10);
6390 OSMetaClassDefineReservedUnused(IOUserClient, 11);
6391 OSMetaClassDefineReservedUnused(IOUserClient, 12);
6392 OSMetaClassDefineReservedUnused(IOUserClient, 13);
6393 OSMetaClassDefineReservedUnused(IOUserClient, 14);
6394 OSMetaClassDefineReservedUnused(IOUserClient, 15);
6395