xref: /xnu-8020.101.4/iokit/Kernel/IOUserClient.cpp (revision e7776783b89a353188416a9a346c6cdb4928faad) !
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 			len = data->getLength();
4745 			*var_outputCnt = len;
4746 			ret = copyoutkdata(data->getBytesNoCopy(), len, var_output);
4747 		} else {
4748 			ret = kIOReturnUnderrun;
4749 		}
4750 	}
4751 
4752 	if (inputMD) {
4753 		inputMD->release();
4754 	}
4755 	if (structureVariableOutputData) {
4756 		structureVariableOutputData->release();
4757 	}
4758 
4759 	return ret;
4760 }
4761 
4762 /* Routine io_user_client_method */
4763 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)4764 is_io_connect_method
4765 (
4766 	io_connect_t connection,
4767 	uint32_t selector,
4768 	io_scalar_inband64_t scalar_input,
4769 	mach_msg_type_number_t scalar_inputCnt,
4770 	io_struct_inband_t inband_input,
4771 	mach_msg_type_number_t inband_inputCnt,
4772 	mach_vm_address_t ool_input,
4773 	mach_vm_size_t ool_input_size,
4774 	io_struct_inband_t inband_output,
4775 	mach_msg_type_number_t *inband_outputCnt,
4776 	io_scalar_inband64_t scalar_output,
4777 	mach_msg_type_number_t *scalar_outputCnt,
4778 	mach_vm_address_t ool_output,
4779 	mach_vm_size_t *ool_output_size
4780 )
4781 {
4782 	CHECK( IOUserClient, connection, client );
4783 
4784 	IOExternalMethodArguments args;
4785 	IOReturn ret;
4786 	IOMemoryDescriptor * inputMD  = NULL;
4787 	IOMemoryDescriptor * outputMD = NULL;
4788 
4789 	bzero(&args.__reserved[0], sizeof(args.__reserved));
4790 	args.__reservedA = 0;
4791 	args.version = kIOExternalMethodArgumentsCurrentVersion;
4792 
4793 	args.selector = selector;
4794 
4795 	args.asyncWakePort               = MACH_PORT_NULL;
4796 	args.asyncReference              = NULL;
4797 	args.asyncReferenceCount         = 0;
4798 	args.structureVariableOutputData = NULL;
4799 
4800 	args.scalarInput = scalar_input;
4801 	args.scalarInputCount = scalar_inputCnt;
4802 	args.structureInput = inband_input;
4803 	args.structureInputSize = inband_inputCnt;
4804 
4805 	if (ool_input && (ool_input_size <= sizeof(io_struct_inband_t))) {
4806 		return kIOReturnIPCError;
4807 	}
4808 	if (ool_output) {
4809 		if (*ool_output_size <= sizeof(io_struct_inband_t)) {
4810 			return kIOReturnIPCError;
4811 		}
4812 		if (*ool_output_size > UINT_MAX) {
4813 			return kIOReturnIPCError;
4814 		}
4815 	}
4816 
4817 	if (ool_input) {
4818 		inputMD = IOMemoryDescriptor::withAddressRange(ool_input, ool_input_size,
4819 		    kIODirectionOut | kIOMemoryMapCopyOnWrite,
4820 		    current_task());
4821 	}
4822 
4823 	args.structureInputDescriptor = inputMD;
4824 
4825 	args.scalarOutput = scalar_output;
4826 	args.scalarOutputCount = *scalar_outputCnt;
4827 	bzero(&scalar_output[0], *scalar_outputCnt * sizeof(scalar_output[0]));
4828 	args.structureOutput = inband_output;
4829 	args.structureOutputSize = *inband_outputCnt;
4830 
4831 	if (ool_output && ool_output_size) {
4832 		outputMD = IOMemoryDescriptor::withAddressRange(ool_output, *ool_output_size,
4833 		    kIODirectionIn, current_task());
4834 	}
4835 
4836 	args.structureOutputDescriptor = outputMD;
4837 	args.structureOutputDescriptorSize = ool_output_size
4838 	    ? ((typeof(args.structureOutputDescriptorSize)) * ool_output_size)
4839 	    : 0;
4840 
4841 	IOStatisticsClientCall();
4842 	ret = kIOReturnSuccess;
4843 	io_filter_policy_t filterPolicy = client->filterForTask(current_task(), 0);
4844 	if (filterPolicy && gIOUCFilterCallbacks->io_filter_applier) {
4845 		ret = gIOUCFilterCallbacks->io_filter_applier(client, filterPolicy, io_filter_type_external_method, selector);
4846 	}
4847 	if (kIOReturnSuccess == ret) {
4848 		if (client->defaultLocking) {
4849 			IORWLockRead(client->lock);
4850 		}
4851 		ret = client->externalMethod( selector, &args );
4852 		if (client->defaultLocking) {
4853 			IORWLockUnlock(client->lock);
4854 		}
4855 	}
4856 
4857 	*scalar_outputCnt = args.scalarOutputCount;
4858 	*inband_outputCnt = args.structureOutputSize;
4859 	*ool_output_size  = args.structureOutputDescriptorSize;
4860 
4861 	if (inputMD) {
4862 		inputMD->release();
4863 	}
4864 	if (outputMD) {
4865 		outputMD->release();
4866 	}
4867 
4868 	return ret;
4869 }
4870 
4871 /* Routine io_async_user_client_method */
4872 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)4873 is_io_connect_async_method
4874 (
4875 	io_connect_t connection,
4876 	mach_port_t wake_port,
4877 	io_async_ref64_t reference,
4878 	mach_msg_type_number_t referenceCnt,
4879 	uint32_t selector,
4880 	io_scalar_inband64_t scalar_input,
4881 	mach_msg_type_number_t scalar_inputCnt,
4882 	io_struct_inband_t inband_input,
4883 	mach_msg_type_number_t inband_inputCnt,
4884 	mach_vm_address_t ool_input,
4885 	mach_vm_size_t ool_input_size,
4886 	io_struct_inband_t inband_output,
4887 	mach_msg_type_number_t *inband_outputCnt,
4888 	io_scalar_inband64_t scalar_output,
4889 	mach_msg_type_number_t *scalar_outputCnt,
4890 	mach_vm_address_t ool_output,
4891 	mach_vm_size_t * ool_output_size
4892 )
4893 {
4894 	CHECK( IOUserClient, connection, client );
4895 
4896 	IOExternalMethodArguments args;
4897 	IOReturn ret;
4898 	IOMemoryDescriptor * inputMD  = NULL;
4899 	IOMemoryDescriptor * outputMD = NULL;
4900 
4901 	if (referenceCnt < 1) {
4902 		return kIOReturnBadArgument;
4903 	}
4904 
4905 	bzero(&args.__reserved[0], sizeof(args.__reserved));
4906 	args.__reservedA = 0;
4907 	args.version = kIOExternalMethodArgumentsCurrentVersion;
4908 
4909 	reference[0]             = (io_user_reference_t) wake_port;
4910 	if (vm_map_is_64bit(get_task_map(current_task()))) {
4911 		reference[0]         |= kIOUCAsync64Flag;
4912 	}
4913 
4914 	args.selector = selector;
4915 
4916 	args.asyncWakePort       = wake_port;
4917 	args.asyncReference      = reference;
4918 	args.asyncReferenceCount = referenceCnt;
4919 
4920 	args.structureVariableOutputData = NULL;
4921 
4922 	args.scalarInput = scalar_input;
4923 	args.scalarInputCount = scalar_inputCnt;
4924 	args.structureInput = inband_input;
4925 	args.structureInputSize = inband_inputCnt;
4926 
4927 	if (ool_input && (ool_input_size <= sizeof(io_struct_inband_t))) {
4928 		return kIOReturnIPCError;
4929 	}
4930 	if (ool_output) {
4931 		if (*ool_output_size <= sizeof(io_struct_inband_t)) {
4932 			return kIOReturnIPCError;
4933 		}
4934 		if (*ool_output_size > UINT_MAX) {
4935 			return kIOReturnIPCError;
4936 		}
4937 	}
4938 
4939 	if (ool_input) {
4940 		inputMD = IOMemoryDescriptor::withAddressRange(ool_input, ool_input_size,
4941 		    kIODirectionOut | kIOMemoryMapCopyOnWrite,
4942 		    current_task());
4943 	}
4944 
4945 	args.structureInputDescriptor = inputMD;
4946 
4947 	args.scalarOutput = scalar_output;
4948 	args.scalarOutputCount = *scalar_outputCnt;
4949 	bzero(&scalar_output[0], *scalar_outputCnt * sizeof(scalar_output[0]));
4950 	args.structureOutput = inband_output;
4951 	args.structureOutputSize = *inband_outputCnt;
4952 
4953 	if (ool_output) {
4954 		outputMD = IOMemoryDescriptor::withAddressRange(ool_output, *ool_output_size,
4955 		    kIODirectionIn, current_task());
4956 	}
4957 
4958 	args.structureOutputDescriptor = outputMD;
4959 	args.structureOutputDescriptorSize = ((typeof(args.structureOutputDescriptorSize)) * ool_output_size);
4960 
4961 	IOStatisticsClientCall();
4962 	ret = kIOReturnSuccess;
4963 	io_filter_policy_t filterPolicy = client->filterForTask(current_task(), 0);
4964 	if (filterPolicy && gIOUCFilterCallbacks->io_filter_applier) {
4965 		ret = gIOUCFilterCallbacks->io_filter_applier(client, filterPolicy, io_filter_type_external_async_method, selector);
4966 	}
4967 	if (kIOReturnSuccess == ret) {
4968 		if (client->defaultLocking) {
4969 			IORWLockRead(client->lock);
4970 		}
4971 		ret = client->externalMethod( selector, &args );
4972 		if (client->defaultLocking) {
4973 			IORWLockUnlock(client->lock);
4974 		}
4975 	}
4976 
4977 	*scalar_outputCnt = args.scalarOutputCount;
4978 	*inband_outputCnt = args.structureOutputSize;
4979 	*ool_output_size  = args.structureOutputDescriptorSize;
4980 
4981 	if (inputMD) {
4982 		inputMD->release();
4983 	}
4984 	if (outputMD) {
4985 		outputMD->release();
4986 	}
4987 
4988 	return ret;
4989 }
4990 
4991 /* Routine io_connect_method_scalarI_scalarO */
4992 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)4993 is_io_connect_method_scalarI_scalarO(
4994 	io_object_t        connect,
4995 	uint32_t           index,
4996 	io_scalar_inband_t       input,
4997 	mach_msg_type_number_t   inputCount,
4998 	io_scalar_inband_t       output,
4999 	mach_msg_type_number_t * outputCount )
5000 {
5001 	IOReturn err;
5002 	uint32_t i;
5003 	io_scalar_inband64_t _input;
5004 	io_scalar_inband64_t _output;
5005 
5006 	mach_msg_type_number_t struct_outputCnt = 0;
5007 	mach_vm_size_t ool_output_size = 0;
5008 
5009 	bzero(&_output[0], sizeof(_output));
5010 	for (i = 0; i < inputCount; i++) {
5011 		_input[i] = SCALAR64(input[i]);
5012 	}
5013 
5014 	err = is_io_connect_method(connect, index,
5015 	    _input, inputCount,
5016 	    NULL, 0,
5017 	    0, 0,
5018 	    NULL, &struct_outputCnt,
5019 	    _output, outputCount,
5020 	    0, &ool_output_size);
5021 
5022 	for (i = 0; i < *outputCount; i++) {
5023 		output[i] = SCALAR32(_output[i]);
5024 	}
5025 
5026 	return err;
5027 }
5028 
5029 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)5030 shim_io_connect_method_scalarI_scalarO(
5031 	IOExternalMethod *      method,
5032 	IOService *             object,
5033 	const io_user_scalar_t * input,
5034 	mach_msg_type_number_t   inputCount,
5035 	io_user_scalar_t * output,
5036 	mach_msg_type_number_t * outputCount )
5037 {
5038 	IOMethod            func;
5039 	io_scalar_inband_t  _output;
5040 	IOReturn            err;
5041 	err = kIOReturnBadArgument;
5042 
5043 	bzero(&_output[0], sizeof(_output));
5044 	do {
5045 		if (inputCount != method->count0) {
5046 			IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0);
5047 			DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0);
5048 			continue;
5049 		}
5050 		if (*outputCount != method->count1) {
5051 			IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)*outputCount, (uint64_t)method->count1);
5052 			DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)*outputCount, uint64_t, (uint64_t)method->count1);
5053 			continue;
5054 		}
5055 
5056 		func = method->func;
5057 
5058 		switch (inputCount) {
5059 		case 6:
5060 			err = (object->*func)(  ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5061 			    ARG32(input[3]), ARG32(input[4]), ARG32(input[5]));
5062 			break;
5063 		case 5:
5064 			err = (object->*func)(  ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5065 			    ARG32(input[3]), ARG32(input[4]),
5066 			    &_output[0] );
5067 			break;
5068 		case 4:
5069 			err = (object->*func)(  ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5070 			    ARG32(input[3]),
5071 			    &_output[0], &_output[1] );
5072 			break;
5073 		case 3:
5074 			err = (object->*func)(  ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5075 			    &_output[0], &_output[1], &_output[2] );
5076 			break;
5077 		case 2:
5078 			err = (object->*func)(  ARG32(input[0]), ARG32(input[1]),
5079 			    &_output[0], &_output[1], &_output[2],
5080 			    &_output[3] );
5081 			break;
5082 		case 1:
5083 			err = (object->*func)(  ARG32(input[0]),
5084 			    &_output[0], &_output[1], &_output[2],
5085 			    &_output[3], &_output[4] );
5086 			break;
5087 		case 0:
5088 			err = (object->*func)(  &_output[0], &_output[1], &_output[2],
5089 			    &_output[3], &_output[4], &_output[5] );
5090 			break;
5091 
5092 		default:
5093 			IOLog("%s: Bad method table\n", object->getName());
5094 		}
5095 	}while (false);
5096 
5097 	uint32_t i;
5098 	for (i = 0; i < *outputCount; i++) {
5099 		output[i] = SCALAR32(_output[i]);
5100 	}
5101 
5102 	return err;
5103 }
5104 
5105 /* Routine io_async_method_scalarI_scalarO */
5106 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)5107 is_io_async_method_scalarI_scalarO(
5108 	io_object_t        connect,
5109 	mach_port_t wake_port,
5110 	io_async_ref_t reference,
5111 	mach_msg_type_number_t referenceCnt,
5112 	uint32_t           index,
5113 	io_scalar_inband_t       input,
5114 	mach_msg_type_number_t   inputCount,
5115 	io_scalar_inband_t       output,
5116 	mach_msg_type_number_t * outputCount )
5117 {
5118 	IOReturn err;
5119 	uint32_t i;
5120 	io_scalar_inband64_t _input;
5121 	io_scalar_inband64_t _output;
5122 	io_async_ref64_t _reference;
5123 
5124 	if (referenceCnt > ASYNC_REF64_COUNT) {
5125 		return kIOReturnBadArgument;
5126 	}
5127 	bzero(&_output[0], sizeof(_output));
5128 	for (i = 0; i < referenceCnt; i++) {
5129 		_reference[i] = REF64(reference[i]);
5130 	}
5131 	bzero(&_reference[referenceCnt], (ASYNC_REF64_COUNT - referenceCnt) * sizeof(_reference[0]));
5132 
5133 	mach_msg_type_number_t struct_outputCnt = 0;
5134 	mach_vm_size_t ool_output_size = 0;
5135 
5136 	for (i = 0; i < inputCount; i++) {
5137 		_input[i] = SCALAR64(input[i]);
5138 	}
5139 
5140 	err = is_io_connect_async_method(connect,
5141 	    wake_port, _reference, referenceCnt,
5142 	    index,
5143 	    _input, inputCount,
5144 	    NULL, 0,
5145 	    0, 0,
5146 	    NULL, &struct_outputCnt,
5147 	    _output, outputCount,
5148 	    0, &ool_output_size);
5149 
5150 	for (i = 0; i < *outputCount; i++) {
5151 		output[i] = SCALAR32(_output[i]);
5152 	}
5153 
5154 	return err;
5155 }
5156 /* Routine io_async_method_scalarI_structureO */
5157 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)5158 is_io_async_method_scalarI_structureO(
5159 	io_object_t     connect,
5160 	mach_port_t wake_port,
5161 	io_async_ref_t reference,
5162 	mach_msg_type_number_t referenceCnt,
5163 	uint32_t        index,
5164 	io_scalar_inband_t input,
5165 	mach_msg_type_number_t  inputCount,
5166 	io_struct_inband_t              output,
5167 	mach_msg_type_number_t *        outputCount )
5168 {
5169 	uint32_t i;
5170 	io_scalar_inband64_t _input;
5171 	io_async_ref64_t _reference;
5172 
5173 	if (referenceCnt > ASYNC_REF64_COUNT) {
5174 		return kIOReturnBadArgument;
5175 	}
5176 	for (i = 0; i < referenceCnt; i++) {
5177 		_reference[i] = REF64(reference[i]);
5178 	}
5179 	bzero(&_reference[referenceCnt], (ASYNC_REF64_COUNT - referenceCnt) * sizeof(_reference[0]));
5180 
5181 	mach_msg_type_number_t scalar_outputCnt = 0;
5182 	mach_vm_size_t ool_output_size = 0;
5183 
5184 	for (i = 0; i < inputCount; i++) {
5185 		_input[i] = SCALAR64(input[i]);
5186 	}
5187 
5188 	return is_io_connect_async_method(connect,
5189 	           wake_port, _reference, referenceCnt,
5190 	           index,
5191 	           _input, inputCount,
5192 	           NULL, 0,
5193 	           0, 0,
5194 	           output, outputCount,
5195 	           NULL, &scalar_outputCnt,
5196 	           0, &ool_output_size);
5197 }
5198 
5199 /* Routine io_async_method_scalarI_structureI */
5200 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)5201 is_io_async_method_scalarI_structureI(
5202 	io_connect_t            connect,
5203 	mach_port_t wake_port,
5204 	io_async_ref_t reference,
5205 	mach_msg_type_number_t referenceCnt,
5206 	uint32_t                index,
5207 	io_scalar_inband_t      input,
5208 	mach_msg_type_number_t  inputCount,
5209 	io_struct_inband_t      inputStruct,
5210 	mach_msg_type_number_t  inputStructCount )
5211 {
5212 	uint32_t i;
5213 	io_scalar_inband64_t _input;
5214 	io_async_ref64_t _reference;
5215 
5216 	if (referenceCnt > ASYNC_REF64_COUNT) {
5217 		return kIOReturnBadArgument;
5218 	}
5219 	for (i = 0; i < referenceCnt; i++) {
5220 		_reference[i] = REF64(reference[i]);
5221 	}
5222 	bzero(&_reference[referenceCnt], (ASYNC_REF64_COUNT - referenceCnt) * sizeof(_reference[0]));
5223 
5224 	mach_msg_type_number_t scalar_outputCnt = 0;
5225 	mach_msg_type_number_t inband_outputCnt = 0;
5226 	mach_vm_size_t ool_output_size = 0;
5227 
5228 	for (i = 0; i < inputCount; i++) {
5229 		_input[i] = SCALAR64(input[i]);
5230 	}
5231 
5232 	return is_io_connect_async_method(connect,
5233 	           wake_port, _reference, referenceCnt,
5234 	           index,
5235 	           _input, inputCount,
5236 	           inputStruct, inputStructCount,
5237 	           0, 0,
5238 	           NULL, &inband_outputCnt,
5239 	           NULL, &scalar_outputCnt,
5240 	           0, &ool_output_size);
5241 }
5242 
5243 /* Routine io_async_method_structureI_structureO */
5244 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)5245 is_io_async_method_structureI_structureO(
5246 	io_object_t     connect,
5247 	mach_port_t wake_port,
5248 	io_async_ref_t reference,
5249 	mach_msg_type_number_t referenceCnt,
5250 	uint32_t        index,
5251 	io_struct_inband_t              input,
5252 	mach_msg_type_number_t  inputCount,
5253 	io_struct_inband_t              output,
5254 	mach_msg_type_number_t *        outputCount )
5255 {
5256 	uint32_t i;
5257 	mach_msg_type_number_t scalar_outputCnt = 0;
5258 	mach_vm_size_t ool_output_size = 0;
5259 	io_async_ref64_t _reference;
5260 
5261 	if (referenceCnt > ASYNC_REF64_COUNT) {
5262 		return kIOReturnBadArgument;
5263 	}
5264 	for (i = 0; i < referenceCnt; i++) {
5265 		_reference[i] = REF64(reference[i]);
5266 	}
5267 	bzero(&_reference[referenceCnt], (ASYNC_REF64_COUNT - referenceCnt) * sizeof(_reference[0]));
5268 
5269 	return is_io_connect_async_method(connect,
5270 	           wake_port, _reference, referenceCnt,
5271 	           index,
5272 	           NULL, 0,
5273 	           input, inputCount,
5274 	           0, 0,
5275 	           output, outputCount,
5276 	           NULL, &scalar_outputCnt,
5277 	           0, &ool_output_size);
5278 }
5279 
5280 
5281 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)5282 shim_io_async_method_scalarI_scalarO(
5283 	IOExternalAsyncMethod * method,
5284 	IOService *             object,
5285 	mach_port_t             asyncWakePort,
5286 	io_user_reference_t *   asyncReference,
5287 	uint32_t                asyncReferenceCount,
5288 	const io_user_scalar_t * input,
5289 	mach_msg_type_number_t   inputCount,
5290 	io_user_scalar_t * output,
5291 	mach_msg_type_number_t * outputCount )
5292 {
5293 	IOAsyncMethod       func;
5294 	uint32_t            i;
5295 	io_scalar_inband_t  _output;
5296 	IOReturn            err;
5297 	io_async_ref_t      reference;
5298 
5299 	bzero(&_output[0], sizeof(_output));
5300 	for (i = 0; i < asyncReferenceCount; i++) {
5301 		reference[i] = REF32(asyncReference[i]);
5302 	}
5303 
5304 	err = kIOReturnBadArgument;
5305 
5306 	do {
5307 		if (inputCount != method->count0) {
5308 			IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0);
5309 			DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0);
5310 			continue;
5311 		}
5312 		if (*outputCount != method->count1) {
5313 			IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)*outputCount, (uint64_t)method->count1);
5314 			DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)*outputCount, uint64_t, (uint64_t)method->count1);
5315 			continue;
5316 		}
5317 
5318 		func = method->func;
5319 
5320 		switch (inputCount) {
5321 		case 6:
5322 			err = (object->*func)(  reference,
5323 			    ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5324 			    ARG32(input[3]), ARG32(input[4]), ARG32(input[5]));
5325 			break;
5326 		case 5:
5327 			err = (object->*func)(  reference,
5328 			    ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5329 			    ARG32(input[3]), ARG32(input[4]),
5330 			    &_output[0] );
5331 			break;
5332 		case 4:
5333 			err = (object->*func)(  reference,
5334 			    ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5335 			    ARG32(input[3]),
5336 			    &_output[0], &_output[1] );
5337 			break;
5338 		case 3:
5339 			err = (object->*func)(  reference,
5340 			    ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5341 			    &_output[0], &_output[1], &_output[2] );
5342 			break;
5343 		case 2:
5344 			err = (object->*func)(  reference,
5345 			    ARG32(input[0]), ARG32(input[1]),
5346 			    &_output[0], &_output[1], &_output[2],
5347 			    &_output[3] );
5348 			break;
5349 		case 1:
5350 			err = (object->*func)(  reference,
5351 			    ARG32(input[0]),
5352 			    &_output[0], &_output[1], &_output[2],
5353 			    &_output[3], &_output[4] );
5354 			break;
5355 		case 0:
5356 			err = (object->*func)(  reference,
5357 			    &_output[0], &_output[1], &_output[2],
5358 			    &_output[3], &_output[4], &_output[5] );
5359 			break;
5360 
5361 		default:
5362 			IOLog("%s: Bad method table\n", object->getName());
5363 		}
5364 	}while (false);
5365 
5366 	for (i = 0; i < *outputCount; i++) {
5367 		output[i] = SCALAR32(_output[i]);
5368 	}
5369 
5370 	return err;
5371 }
5372 
5373 
5374 /* Routine io_connect_method_scalarI_structureO */
5375 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)5376 is_io_connect_method_scalarI_structureO(
5377 	io_object_t     connect,
5378 	uint32_t        index,
5379 	io_scalar_inband_t input,
5380 	mach_msg_type_number_t  inputCount,
5381 	io_struct_inband_t              output,
5382 	mach_msg_type_number_t *        outputCount )
5383 {
5384 	uint32_t i;
5385 	io_scalar_inband64_t _input;
5386 
5387 	mach_msg_type_number_t scalar_outputCnt = 0;
5388 	mach_vm_size_t ool_output_size = 0;
5389 
5390 	for (i = 0; i < inputCount; i++) {
5391 		_input[i] = SCALAR64(input[i]);
5392 	}
5393 
5394 	return is_io_connect_method(connect, index,
5395 	           _input, inputCount,
5396 	           NULL, 0,
5397 	           0, 0,
5398 	           output, outputCount,
5399 	           NULL, &scalar_outputCnt,
5400 	           0, &ool_output_size);
5401 }
5402 
5403 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)5404 shim_io_connect_method_scalarI_structureO(
5405 
5406 	IOExternalMethod *      method,
5407 	IOService *             object,
5408 	const io_user_scalar_t * input,
5409 	mach_msg_type_number_t  inputCount,
5410 	io_struct_inband_t              output,
5411 	IOByteCount *   outputCount )
5412 {
5413 	IOMethod            func;
5414 	IOReturn            err;
5415 
5416 	err = kIOReturnBadArgument;
5417 
5418 	do {
5419 		if (inputCount != method->count0) {
5420 			IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0);
5421 			DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0);
5422 			continue;
5423 		}
5424 		if ((kIOUCVariableStructureSize != method->count1)
5425 		    && (*outputCount != method->count1)) {
5426 			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);
5427 			DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)*outputCount, uint64_t, (uint64_t)method->count1);
5428 			continue;
5429 		}
5430 
5431 		func = method->func;
5432 
5433 		switch (inputCount) {
5434 		case 5:
5435 			err = (object->*func)(  ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5436 			    ARG32(input[3]), ARG32(input[4]),
5437 			    output );
5438 			break;
5439 		case 4:
5440 			err = (object->*func)(  ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5441 			    ARG32(input[3]),
5442 			    output, (void *)outputCount );
5443 			break;
5444 		case 3:
5445 			err = (object->*func)(  ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5446 			    output, (void *)outputCount, NULL );
5447 			break;
5448 		case 2:
5449 			err = (object->*func)(  ARG32(input[0]), ARG32(input[1]),
5450 			    output, (void *)outputCount, NULL, NULL );
5451 			break;
5452 		case 1:
5453 			err = (object->*func)(  ARG32(input[0]),
5454 			    output, (void *)outputCount, NULL, NULL, NULL );
5455 			break;
5456 		case 0:
5457 			err = (object->*func)(  output, (void *)outputCount, NULL, NULL, NULL, NULL );
5458 			break;
5459 
5460 		default:
5461 			IOLog("%s: Bad method table\n", object->getName());
5462 		}
5463 	}while (false);
5464 
5465 	return err;
5466 }
5467 
5468 
5469 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)5470 shim_io_async_method_scalarI_structureO(
5471 	IOExternalAsyncMethod * method,
5472 	IOService *             object,
5473 	mach_port_t             asyncWakePort,
5474 	io_user_reference_t *   asyncReference,
5475 	uint32_t                asyncReferenceCount,
5476 	const io_user_scalar_t * input,
5477 	mach_msg_type_number_t  inputCount,
5478 	io_struct_inband_t              output,
5479 	mach_msg_type_number_t *        outputCount )
5480 {
5481 	IOAsyncMethod       func;
5482 	uint32_t            i;
5483 	IOReturn            err;
5484 	io_async_ref_t      reference;
5485 
5486 	for (i = 0; i < asyncReferenceCount; i++) {
5487 		reference[i] = REF32(asyncReference[i]);
5488 	}
5489 
5490 	err = kIOReturnBadArgument;
5491 	do {
5492 		if (inputCount != method->count0) {
5493 			IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0);
5494 			DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0);
5495 			continue;
5496 		}
5497 		if ((kIOUCVariableStructureSize != method->count1)
5498 		    && (*outputCount != method->count1)) {
5499 			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);
5500 			DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)*outputCount, uint64_t, (uint64_t)method->count1);
5501 			continue;
5502 		}
5503 
5504 		func = method->func;
5505 
5506 		switch (inputCount) {
5507 		case 5:
5508 			err = (object->*func)(  reference,
5509 			    ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5510 			    ARG32(input[3]), ARG32(input[4]),
5511 			    output );
5512 			break;
5513 		case 4:
5514 			err = (object->*func)(  reference,
5515 			    ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5516 			    ARG32(input[3]),
5517 			    output, (void *)outputCount );
5518 			break;
5519 		case 3:
5520 			err = (object->*func)(  reference,
5521 			    ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5522 			    output, (void *)outputCount, NULL );
5523 			break;
5524 		case 2:
5525 			err = (object->*func)(  reference,
5526 			    ARG32(input[0]), ARG32(input[1]),
5527 			    output, (void *)outputCount, NULL, NULL );
5528 			break;
5529 		case 1:
5530 			err = (object->*func)(  reference,
5531 			    ARG32(input[0]),
5532 			    output, (void *)outputCount, NULL, NULL, NULL );
5533 			break;
5534 		case 0:
5535 			err = (object->*func)(  reference,
5536 			    output, (void *)outputCount, NULL, NULL, NULL, NULL );
5537 			break;
5538 
5539 		default:
5540 			IOLog("%s: Bad method table\n", object->getName());
5541 		}
5542 	}while (false);
5543 
5544 	return err;
5545 }
5546 
5547 /* Routine io_connect_method_scalarI_structureI */
5548 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)5549 is_io_connect_method_scalarI_structureI(
5550 	io_connect_t            connect,
5551 	uint32_t                index,
5552 	io_scalar_inband_t      input,
5553 	mach_msg_type_number_t  inputCount,
5554 	io_struct_inband_t      inputStruct,
5555 	mach_msg_type_number_t  inputStructCount )
5556 {
5557 	uint32_t i;
5558 	io_scalar_inband64_t _input;
5559 
5560 	mach_msg_type_number_t scalar_outputCnt = 0;
5561 	mach_msg_type_number_t inband_outputCnt = 0;
5562 	mach_vm_size_t ool_output_size = 0;
5563 
5564 	for (i = 0; i < inputCount; i++) {
5565 		_input[i] = SCALAR64(input[i]);
5566 	}
5567 
5568 	return is_io_connect_method(connect, index,
5569 	           _input, inputCount,
5570 	           inputStruct, inputStructCount,
5571 	           0, 0,
5572 	           NULL, &inband_outputCnt,
5573 	           NULL, &scalar_outputCnt,
5574 	           0, &ool_output_size);
5575 }
5576 
5577 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)5578 shim_io_connect_method_scalarI_structureI(
5579 	IOExternalMethod *  method,
5580 	IOService *         object,
5581 	const io_user_scalar_t * input,
5582 	mach_msg_type_number_t  inputCount,
5583 	io_struct_inband_t              inputStruct,
5584 	mach_msg_type_number_t  inputStructCount )
5585 {
5586 	IOMethod            func;
5587 	IOReturn            err = kIOReturnBadArgument;
5588 
5589 	do{
5590 		if (inputCount != method->count0) {
5591 			IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0);
5592 			DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0);
5593 			continue;
5594 		}
5595 		if ((kIOUCVariableStructureSize != method->count1)
5596 		    && (inputStructCount != method->count1)) {
5597 			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);
5598 			DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputStructCount, uint64_t, (uint64_t)method->count1);
5599 			continue;
5600 		}
5601 
5602 		func = method->func;
5603 
5604 		switch (inputCount) {
5605 		case 5:
5606 			err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5607 			    ARG32(input[3]), ARG32(input[4]),
5608 			    inputStruct );
5609 			break;
5610 		case 4:
5611 			err = (object->*func)( ARG32(input[0]), ARG32(input[1]), (void *)  input[2],
5612 			    ARG32(input[3]),
5613 			    inputStruct, (void *)(uintptr_t)inputStructCount );
5614 			break;
5615 		case 3:
5616 			err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5617 			    inputStruct, (void *)(uintptr_t)inputStructCount,
5618 			    NULL );
5619 			break;
5620 		case 2:
5621 			err = (object->*func)( ARG32(input[0]), ARG32(input[1]),
5622 			    inputStruct, (void *)(uintptr_t)inputStructCount,
5623 			    NULL, NULL );
5624 			break;
5625 		case 1:
5626 			err = (object->*func)( ARG32(input[0]),
5627 			    inputStruct, (void *)(uintptr_t)inputStructCount,
5628 			    NULL, NULL, NULL );
5629 			break;
5630 		case 0:
5631 			err = (object->*func)( inputStruct, (void *)(uintptr_t)inputStructCount,
5632 			    NULL, NULL, NULL, NULL );
5633 			break;
5634 
5635 		default:
5636 			IOLog("%s: Bad method table\n", object->getName());
5637 		}
5638 	}while (false);
5639 
5640 	return err;
5641 }
5642 
5643 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)5644 shim_io_async_method_scalarI_structureI(
5645 	IOExternalAsyncMethod * method,
5646 	IOService *             object,
5647 	mach_port_t             asyncWakePort,
5648 	io_user_reference_t *   asyncReference,
5649 	uint32_t                asyncReferenceCount,
5650 	const io_user_scalar_t * input,
5651 	mach_msg_type_number_t  inputCount,
5652 	io_struct_inband_t              inputStruct,
5653 	mach_msg_type_number_t  inputStructCount )
5654 {
5655 	IOAsyncMethod       func;
5656 	uint32_t            i;
5657 	IOReturn            err = kIOReturnBadArgument;
5658 	io_async_ref_t      reference;
5659 
5660 	for (i = 0; i < asyncReferenceCount; i++) {
5661 		reference[i] = REF32(asyncReference[i]);
5662 	}
5663 
5664 	do{
5665 		if (inputCount != method->count0) {
5666 			IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0);
5667 			DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0);
5668 			continue;
5669 		}
5670 		if ((kIOUCVariableStructureSize != method->count1)
5671 		    && (inputStructCount != method->count1)) {
5672 			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);
5673 			DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputStructCount, uint64_t, (uint64_t)method->count1);
5674 			continue;
5675 		}
5676 
5677 		func = method->func;
5678 
5679 		switch (inputCount) {
5680 		case 5:
5681 			err = (object->*func)(  reference,
5682 			    ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5683 			    ARG32(input[3]), ARG32(input[4]),
5684 			    inputStruct );
5685 			break;
5686 		case 4:
5687 			err = (object->*func)(  reference,
5688 			    ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5689 			    ARG32(input[3]),
5690 			    inputStruct, (void *)(uintptr_t)inputStructCount );
5691 			break;
5692 		case 3:
5693 			err = (object->*func)(  reference,
5694 			    ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5695 			    inputStruct, (void *)(uintptr_t)inputStructCount,
5696 			    NULL );
5697 			break;
5698 		case 2:
5699 			err = (object->*func)(  reference,
5700 			    ARG32(input[0]), ARG32(input[1]),
5701 			    inputStruct, (void *)(uintptr_t)inputStructCount,
5702 			    NULL, NULL );
5703 			break;
5704 		case 1:
5705 			err = (object->*func)(  reference,
5706 			    ARG32(input[0]),
5707 			    inputStruct, (void *)(uintptr_t)inputStructCount,
5708 			    NULL, NULL, NULL );
5709 			break;
5710 		case 0:
5711 			err = (object->*func)(  reference,
5712 			    inputStruct, (void *)(uintptr_t)inputStructCount,
5713 			    NULL, NULL, NULL, NULL );
5714 			break;
5715 
5716 		default:
5717 			IOLog("%s: Bad method table\n", object->getName());
5718 		}
5719 	}while (false);
5720 
5721 	return err;
5722 }
5723 
5724 /* Routine io_connect_method_structureI_structureO */
5725 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)5726 is_io_connect_method_structureI_structureO(
5727 	io_object_t     connect,
5728 	uint32_t        index,
5729 	io_struct_inband_t              input,
5730 	mach_msg_type_number_t  inputCount,
5731 	io_struct_inband_t              output,
5732 	mach_msg_type_number_t *        outputCount )
5733 {
5734 	mach_msg_type_number_t scalar_outputCnt = 0;
5735 	mach_vm_size_t ool_output_size = 0;
5736 
5737 	return is_io_connect_method(connect, index,
5738 	           NULL, 0,
5739 	           input, inputCount,
5740 	           0, 0,
5741 	           output, outputCount,
5742 	           NULL, &scalar_outputCnt,
5743 	           0, &ool_output_size);
5744 }
5745 
5746 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)5747 shim_io_connect_method_structureI_structureO(
5748 	IOExternalMethod *  method,
5749 	IOService *         object,
5750 	io_struct_inband_t              input,
5751 	mach_msg_type_number_t  inputCount,
5752 	io_struct_inband_t              output,
5753 	IOByteCount *   outputCount )
5754 {
5755 	IOMethod            func;
5756 	IOReturn            err = kIOReturnBadArgument;
5757 
5758 	do{
5759 		if ((kIOUCVariableStructureSize != method->count0)
5760 		    && (inputCount != method->count0)) {
5761 			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);
5762 			DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0);
5763 			continue;
5764 		}
5765 		if ((kIOUCVariableStructureSize != method->count1)
5766 		    && (*outputCount != method->count1)) {
5767 			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);
5768 			DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)*outputCount, uint64_t, (uint64_t)method->count1);
5769 			continue;
5770 		}
5771 
5772 		func = method->func;
5773 
5774 		if (method->count1) {
5775 			if (method->count0) {
5776 				err = (object->*func)( input, output,
5777 				    (void *)(uintptr_t)inputCount, outputCount, NULL, NULL );
5778 			} else {
5779 				err = (object->*func)( output, outputCount, NULL, NULL, NULL, NULL );
5780 			}
5781 		} else {
5782 			err = (object->*func)( input, (void *)(uintptr_t)inputCount, NULL, NULL, NULL, NULL );
5783 		}
5784 	}while (false);
5785 
5786 
5787 	return err;
5788 }
5789 
5790 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)5791 shim_io_async_method_structureI_structureO(
5792 	IOExternalAsyncMethod * method,
5793 	IOService *             object,
5794 	mach_port_t           asyncWakePort,
5795 	io_user_reference_t * asyncReference,
5796 	uint32_t              asyncReferenceCount,
5797 	io_struct_inband_t              input,
5798 	mach_msg_type_number_t  inputCount,
5799 	io_struct_inband_t              output,
5800 	mach_msg_type_number_t *        outputCount )
5801 {
5802 	IOAsyncMethod       func;
5803 	uint32_t            i;
5804 	IOReturn            err;
5805 	io_async_ref_t      reference;
5806 
5807 	for (i = 0; i < asyncReferenceCount; i++) {
5808 		reference[i] = REF32(asyncReference[i]);
5809 	}
5810 
5811 	err = kIOReturnBadArgument;
5812 	do{
5813 		if ((kIOUCVariableStructureSize != method->count0)
5814 		    && (inputCount != method->count0)) {
5815 			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);
5816 			DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0);
5817 			continue;
5818 		}
5819 		if ((kIOUCVariableStructureSize != method->count1)
5820 		    && (*outputCount != method->count1)) {
5821 			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);
5822 			DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)*outputCount, uint64_t, (uint64_t)method->count1);
5823 			continue;
5824 		}
5825 
5826 		func = method->func;
5827 
5828 		if (method->count1) {
5829 			if (method->count0) {
5830 				err = (object->*func)( reference,
5831 				    input, output,
5832 				    (void *)(uintptr_t)inputCount, outputCount, NULL, NULL );
5833 			} else {
5834 				err = (object->*func)( reference,
5835 				    output, outputCount, NULL, NULL, NULL, NULL );
5836 			}
5837 		} else {
5838 			err = (object->*func)( reference,
5839 			    input, (void *)(uintptr_t)inputCount, NULL, NULL, NULL, NULL );
5840 		}
5841 	}while (false);
5842 
5843 	return err;
5844 }
5845 
5846 /* Routine io_catalog_send_data */
5847 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)5848 is_io_catalog_send_data(
5849 	mach_port_t             master_port,
5850 	uint32_t                flag,
5851 	io_buf_ptr_t            inData,
5852 	mach_msg_type_number_t  inDataCount,
5853 	kern_return_t *         result)
5854 {
5855 	// Allow sending catalog data if there is no kextd and the kernel is DEVELOPMENT || DEBUG
5856 #if NO_KEXTD && !(DEVELOPMENT || DEBUG)
5857 	return kIOReturnNotPrivileged;
5858 #else /* NO_KEXTD && !(DEVELOPMENT || DEBUG) */
5859 	OSObject * obj = NULL;
5860 	vm_offset_t data;
5861 	kern_return_t kr = kIOReturnError;
5862 
5863 	//printf("io_catalog_send_data called. flag: %d\n", flag);
5864 
5865 	if (master_port != master_device_port) {
5866 		return kIOReturnNotPrivileged;
5867 	}
5868 
5869 	if ((flag != kIOCatalogRemoveKernelLinker__Removed &&
5870 	    flag != kIOCatalogKextdActive &&
5871 	    flag != kIOCatalogKextdFinishedLaunching) &&
5872 	    (!inData || !inDataCount)) {
5873 		return kIOReturnBadArgument;
5874 	}
5875 
5876 	if (!IOCurrentTaskHasEntitlement(kIOCatalogManagementEntitlement)) {
5877 		OSString * taskName = IOCopyLogNameForPID(proc_selfpid());
5878 		IOLog("IOCatalogueSendData(%s): Not entitled\n", taskName ? taskName->getCStringNoCopy() : "");
5879 		OSSafeReleaseNULL(taskName);
5880 		// For now, fake success to not break applications relying on this function succeeding.
5881 		// See <rdar://problem/32554970> for more details.
5882 		return kIOReturnSuccess;
5883 	}
5884 
5885 	if (inData) {
5886 		vm_map_offset_t map_data;
5887 
5888 		if (inDataCount > sizeof(io_struct_inband_t) * 1024) {
5889 			return kIOReturnMessageTooLarge;
5890 		}
5891 
5892 		kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t)inData);
5893 		data = CAST_DOWN(vm_offset_t, map_data);
5894 
5895 		if (kr != KERN_SUCCESS) {
5896 			return kr;
5897 		}
5898 
5899 		// must return success after vm_map_copyout() succeeds
5900 
5901 		if (inDataCount) {
5902 			obj = (OSObject *)OSUnserializeXML((const char *)data, inDataCount);
5903 			vm_deallocate( kernel_map, data, inDataCount );
5904 			if (!obj) {
5905 				*result = kIOReturnNoMemory;
5906 				return KERN_SUCCESS;
5907 			}
5908 		}
5909 	}
5910 
5911 	switch (flag) {
5912 	case kIOCatalogResetDrivers:
5913 	case kIOCatalogResetDriversNoMatch: {
5914 		OSArray * array;
5915 
5916 		array = OSDynamicCast(OSArray, obj);
5917 		if (array) {
5918 			if (!gIOCatalogue->resetAndAddDrivers(array,
5919 			    flag == kIOCatalogResetDrivers)) {
5920 				kr = kIOReturnError;
5921 			}
5922 		} else {
5923 			kr = kIOReturnBadArgument;
5924 		}
5925 	}
5926 	break;
5927 
5928 	case kIOCatalogAddDrivers:
5929 	case kIOCatalogAddDriversNoMatch: {
5930 		OSArray * array;
5931 
5932 		array = OSDynamicCast(OSArray, obj);
5933 		if (array) {
5934 			if (!gIOCatalogue->addDrivers( array,
5935 			    flag == kIOCatalogAddDrivers)) {
5936 				kr = kIOReturnError;
5937 			}
5938 		} else {
5939 			kr = kIOReturnBadArgument;
5940 		}
5941 	}
5942 	break;
5943 
5944 	case kIOCatalogRemoveDrivers:
5945 	case kIOCatalogRemoveDriversNoMatch: {
5946 		OSDictionary * dict;
5947 
5948 		dict = OSDynamicCast(OSDictionary, obj);
5949 		if (dict) {
5950 			if (!gIOCatalogue->removeDrivers( dict,
5951 			    flag == kIOCatalogRemoveDrivers )) {
5952 				kr = kIOReturnError;
5953 			}
5954 		} else {
5955 			kr = kIOReturnBadArgument;
5956 		}
5957 	}
5958 	break;
5959 
5960 	case kIOCatalogStartMatching__Removed:
5961 	case kIOCatalogRemoveKernelLinker__Removed:
5962 	case kIOCatalogKextdActive:
5963 	case kIOCatalogKextdFinishedLaunching:
5964 		kr = KERN_NOT_SUPPORTED;
5965 		break;
5966 
5967 	default:
5968 		kr = kIOReturnBadArgument;
5969 		break;
5970 	}
5971 
5972 	if (obj) {
5973 		obj->release();
5974 	}
5975 
5976 	*result = kr;
5977 	return KERN_SUCCESS;
5978 #endif /* NO_KEXTD && !(DEVELOPMENT || DEBUG) */
5979 }
5980 
5981 /* Routine io_catalog_terminate */
5982 kern_return_t
is_io_catalog_terminate(mach_port_t master_port,uint32_t flag,io_name_t name)5983 is_io_catalog_terminate(
5984 	mach_port_t master_port,
5985 	uint32_t flag,
5986 	io_name_t name )
5987 {
5988 	kern_return_t          kr;
5989 
5990 	if (master_port != master_device_port) {
5991 		return kIOReturnNotPrivileged;
5992 	}
5993 
5994 	kr = IOUserClient::clientHasPrivilege((void *) current_task(),
5995 	    kIOClientPrivilegeAdministrator );
5996 	if (kIOReturnSuccess != kr) {
5997 		return kr;
5998 	}
5999 
6000 	switch (flag) {
6001 #if !defined(SECURE_KERNEL)
6002 	case kIOCatalogServiceTerminate:
6003 		kr = gIOCatalogue->terminateDrivers(NULL, name);
6004 		break;
6005 
6006 	case kIOCatalogModuleUnload:
6007 	case kIOCatalogModuleTerminate:
6008 		kr = gIOCatalogue->terminateDriversForModule(name,
6009 		    flag == kIOCatalogModuleUnload);
6010 		break;
6011 #endif
6012 
6013 	default:
6014 		kr = kIOReturnBadArgument;
6015 		break;
6016 	}
6017 
6018 	return kr;
6019 }
6020 
6021 /* Routine io_catalog_get_data */
6022 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)6023 is_io_catalog_get_data(
6024 	mach_port_t             master_port,
6025 	uint32_t                flag,
6026 	io_buf_ptr_t            *outData,
6027 	mach_msg_type_number_t  *outDataCount)
6028 {
6029 	kern_return_t kr = kIOReturnSuccess;
6030 	OSSerialize * s;
6031 
6032 	if (master_port != master_device_port) {
6033 		return kIOReturnNotPrivileged;
6034 	}
6035 
6036 	//printf("io_catalog_get_data called. flag: %d\n", flag);
6037 
6038 	s = OSSerialize::withCapacity(4096);
6039 	if (!s) {
6040 		return kIOReturnNoMemory;
6041 	}
6042 
6043 	kr = gIOCatalogue->serializeData(flag, s);
6044 
6045 	if (kr == kIOReturnSuccess) {
6046 		mach_vm_address_t data;
6047 		vm_map_copy_t copy;
6048 		unsigned int size;
6049 
6050 		size = s->getLength();
6051 		kr = mach_vm_allocate_kernel(kernel_map, &data, size, VM_FLAGS_ANYWHERE, VM_KERN_MEMORY_IOKIT);
6052 		if (kr == kIOReturnSuccess) {
6053 			bcopy(s->text(), (void *)data, size);
6054 			kr = vm_map_copyin(kernel_map, data, size, true, &copy);
6055 			*outData = (char *)copy;
6056 			*outDataCount = size;
6057 		}
6058 	}
6059 
6060 	s->release();
6061 
6062 	return kr;
6063 }
6064 
6065 /* Routine io_catalog_get_gen_count */
6066 kern_return_t
is_io_catalog_get_gen_count(mach_port_t master_port,uint32_t * genCount)6067 is_io_catalog_get_gen_count(
6068 	mach_port_t             master_port,
6069 	uint32_t                *genCount)
6070 {
6071 	if (master_port != master_device_port) {
6072 		return kIOReturnNotPrivileged;
6073 	}
6074 
6075 	//printf("io_catalog_get_gen_count called.\n");
6076 
6077 	if (!genCount) {
6078 		return kIOReturnBadArgument;
6079 	}
6080 
6081 	*genCount = gIOCatalogue->getGenerationCount();
6082 
6083 	return kIOReturnSuccess;
6084 }
6085 
6086 /* Routine io_catalog_module_loaded.
6087  * Is invoked from IOKitLib's IOCatalogueModuleLoaded(). Doesn't seem to be used.
6088  */
6089 kern_return_t
is_io_catalog_module_loaded(mach_port_t master_port,io_name_t name)6090 is_io_catalog_module_loaded(
6091 	mach_port_t             master_port,
6092 	io_name_t               name)
6093 {
6094 	if (master_port != master_device_port) {
6095 		return kIOReturnNotPrivileged;
6096 	}
6097 
6098 	//printf("io_catalog_module_loaded called. name %s\n", name);
6099 
6100 	if (!name) {
6101 		return kIOReturnBadArgument;
6102 	}
6103 
6104 	gIOCatalogue->moduleHasLoaded(name);
6105 
6106 	return kIOReturnSuccess;
6107 }
6108 
6109 kern_return_t
is_io_catalog_reset(mach_port_t master_port,uint32_t flag)6110 is_io_catalog_reset(
6111 	mach_port_t             master_port,
6112 	uint32_t                flag)
6113 {
6114 	if (master_port != master_device_port) {
6115 		return kIOReturnNotPrivileged;
6116 	}
6117 
6118 	switch (flag) {
6119 	case kIOCatalogResetDefault:
6120 		gIOCatalogue->reset();
6121 		break;
6122 
6123 	default:
6124 		return kIOReturnBadArgument;
6125 	}
6126 
6127 	return kIOReturnSuccess;
6128 }
6129 
6130 kern_return_t
iokit_user_client_trap(struct iokit_user_client_trap_args * args)6131 iokit_user_client_trap(struct iokit_user_client_trap_args *args)
6132 {
6133 	kern_return_t    result = kIOReturnBadArgument;
6134 	IOUserClient   * userClient;
6135 	OSObject       * object;
6136 	uintptr_t        ref;
6137 	mach_port_name_t portName;
6138 
6139 	ref     = (uintptr_t) args->userClientRef;
6140 
6141 	if ((ref == MACH_PORT_DEAD) || (ref == (uintptr_t) MACH_PORT_NULL)) {
6142 		return kIOReturnBadArgument;
6143 	}
6144 	// kobject port names always have b0-1 set, so we use these bits as flags to
6145 	// iokit_user_client_trap()
6146 	// keep this up to date with ipc_entry_name_mask();
6147 	portName = (mach_port_name_t) (ref | 3);
6148 	if (((1ULL << 32) & ref) || !(1 & ref)) {
6149 		object = iokit_lookup_uext_ref_current_task(portName);
6150 		if (object) {
6151 			result = IOUserServerUEXTTrap(object, args->p1, args->p2, args->p3, args->p4, args->p5, args->p6);
6152 		}
6153 		OSSafeReleaseNULL(object);
6154 	} else {
6155 		io_object_t ref_current_task = iokit_lookup_connect_ref_current_task((mach_port_name_t) ref);
6156 		if ((userClient = OSDynamicCast(IOUserClient, ref_current_task))) {
6157 			IOExternalTrap *trap = NULL;
6158 			IOService *target = NULL;
6159 
6160 			result = kIOReturnSuccess;
6161 			io_filter_policy_t filterPolicy = userClient->filterForTask(current_task(), 0);
6162 			if (filterPolicy && gIOUCFilterCallbacks->io_filter_applier) {
6163 				result = gIOUCFilterCallbacks->io_filter_applier(userClient, filterPolicy, io_filter_type_trap, args->index);
6164 			}
6165 			if (kIOReturnSuccess == result) {
6166 				trap = userClient->getTargetAndTrapForIndex(&target, args->index);
6167 			}
6168 			if (trap && target) {
6169 				IOTrap func;
6170 
6171 				func = trap->func;
6172 
6173 				if (func) {
6174 					result = (target->*func)(args->p1, args->p2, args->p3, args->p4, args->p5, args->p6);
6175 				}
6176 			}
6177 
6178 			iokit_remove_connect_reference(userClient);
6179 		} else {
6180 			OSSafeReleaseNULL(ref_current_task);
6181 		}
6182 	}
6183 
6184 	return result;
6185 }
6186 
6187 /* Routine io_device_tree_entry_exists_with_name */
6188 kern_return_t
is_io_device_tree_entry_exists_with_name(mach_port_t master_port,io_name_t name,boolean_t * exists)6189 is_io_device_tree_entry_exists_with_name(
6190 	mach_port_t master_port,
6191 	io_name_t name,
6192 	boolean_t *exists )
6193 {
6194 	OSCollectionIterator *iter;
6195 
6196 	if (master_port != master_device_port) {
6197 		return kIOReturnNotPrivileged;
6198 	}
6199 
6200 	iter = IODTFindMatchingEntries(IORegistryEntry::getRegistryRoot(), kIODTRecursive, name);
6201 	*exists = iter && iter->getNextObject();
6202 	OSSafeReleaseNULL(iter);
6203 
6204 	return kIOReturnSuccess;
6205 }
6206 } /* extern "C" */
6207 
6208 IOReturn
externalMethod(uint32_t selector,IOExternalMethodArguments * args,IOExternalMethodDispatch * dispatch,OSObject * target,void * reference)6209 IOUserClient::externalMethod( uint32_t selector, IOExternalMethodArguments * args,
6210     IOExternalMethodDispatch * dispatch, OSObject * target, void * reference )
6211 {
6212 	IOReturn    err;
6213 	IOService * object;
6214 	IOByteCount structureOutputSize;
6215 
6216 	if (dispatch) {
6217 		uint32_t count;
6218 		count = dispatch->checkScalarInputCount;
6219 		if ((kIOUCVariableStructureSize != count) && (count != args->scalarInputCount)) {
6220 			return kIOReturnBadArgument;
6221 		}
6222 
6223 		count = dispatch->checkStructureInputSize;
6224 		if ((kIOUCVariableStructureSize != count)
6225 		    && (count != ((args->structureInputDescriptor)
6226 		    ? args->structureInputDescriptor->getLength() : args->structureInputSize))) {
6227 			return kIOReturnBadArgument;
6228 		}
6229 
6230 		count = dispatch->checkScalarOutputCount;
6231 		if ((kIOUCVariableStructureSize != count) && (count != args->scalarOutputCount)) {
6232 			return kIOReturnBadArgument;
6233 		}
6234 
6235 		count = dispatch->checkStructureOutputSize;
6236 		if ((kIOUCVariableStructureSize != count)
6237 		    && (count != ((args->structureOutputDescriptor)
6238 		    ? args->structureOutputDescriptor->getLength() : args->structureOutputSize))) {
6239 			return kIOReturnBadArgument;
6240 		}
6241 
6242 		if (dispatch->function) {
6243 			err = (*dispatch->function)(target, reference, args);
6244 		} else {
6245 			err = kIOReturnNoCompletion; /* implementator can dispatch */
6246 		}
6247 		return err;
6248 	}
6249 
6250 
6251 	// pre-Leopard API's don't do ool structs
6252 	if (args->structureInputDescriptor || args->structureOutputDescriptor) {
6253 		err = kIOReturnIPCError;
6254 		return err;
6255 	}
6256 
6257 	structureOutputSize = args->structureOutputSize;
6258 
6259 	if (args->asyncWakePort) {
6260 		IOExternalAsyncMethod * method;
6261 		object = NULL;
6262 		if (!(method = getAsyncTargetAndMethodForIndex(&object, selector)) || !object) {
6263 			return kIOReturnUnsupported;
6264 		}
6265 
6266 		if (kIOUCForegroundOnly & method->flags) {
6267 			if (task_is_gpu_denied(current_task())) {
6268 				return kIOReturnNotPermitted;
6269 			}
6270 		}
6271 
6272 		switch (method->flags & kIOUCTypeMask) {
6273 		case kIOUCScalarIStructI:
6274 			err = shim_io_async_method_scalarI_structureI( method, object,
6275 			    args->asyncWakePort, args->asyncReference, args->asyncReferenceCount,
6276 			    args->scalarInput, args->scalarInputCount,
6277 			    (char *)args->structureInput, args->structureInputSize );
6278 			break;
6279 
6280 		case kIOUCScalarIScalarO:
6281 			err = shim_io_async_method_scalarI_scalarO( method, object,
6282 			    args->asyncWakePort, args->asyncReference, args->asyncReferenceCount,
6283 			    args->scalarInput, args->scalarInputCount,
6284 			    args->scalarOutput, &args->scalarOutputCount );
6285 			break;
6286 
6287 		case kIOUCScalarIStructO:
6288 			err = shim_io_async_method_scalarI_structureO( method, object,
6289 			    args->asyncWakePort, args->asyncReference, args->asyncReferenceCount,
6290 			    args->scalarInput, args->scalarInputCount,
6291 			    (char *) args->structureOutput, &args->structureOutputSize );
6292 			break;
6293 
6294 
6295 		case kIOUCStructIStructO:
6296 			err = shim_io_async_method_structureI_structureO( method, object,
6297 			    args->asyncWakePort, args->asyncReference, args->asyncReferenceCount,
6298 			    (char *)args->structureInput, args->structureInputSize,
6299 			    (char *) args->structureOutput, &args->structureOutputSize );
6300 			break;
6301 
6302 		default:
6303 			err = kIOReturnBadArgument;
6304 			break;
6305 		}
6306 	} else {
6307 		IOExternalMethod *      method;
6308 		object = NULL;
6309 		if (!(method = getTargetAndMethodForIndex(&object, selector)) || !object) {
6310 			return kIOReturnUnsupported;
6311 		}
6312 
6313 		if (kIOUCForegroundOnly & method->flags) {
6314 			if (task_is_gpu_denied(current_task())) {
6315 				return kIOReturnNotPermitted;
6316 			}
6317 		}
6318 
6319 		switch (method->flags & kIOUCTypeMask) {
6320 		case kIOUCScalarIStructI:
6321 			err = shim_io_connect_method_scalarI_structureI( method, object,
6322 			    args->scalarInput, args->scalarInputCount,
6323 			    (char *) args->structureInput, args->structureInputSize );
6324 			break;
6325 
6326 		case kIOUCScalarIScalarO:
6327 			err = shim_io_connect_method_scalarI_scalarO( method, object,
6328 			    args->scalarInput, args->scalarInputCount,
6329 			    args->scalarOutput, &args->scalarOutputCount );
6330 			break;
6331 
6332 		case kIOUCScalarIStructO:
6333 			err = shim_io_connect_method_scalarI_structureO( method, object,
6334 			    args->scalarInput, args->scalarInputCount,
6335 			    (char *) args->structureOutput, &structureOutputSize );
6336 			break;
6337 
6338 
6339 		case kIOUCStructIStructO:
6340 			err = shim_io_connect_method_structureI_structureO( method, object,
6341 			    (char *) args->structureInput, args->structureInputSize,
6342 			    (char *) args->structureOutput, &structureOutputSize );
6343 			break;
6344 
6345 		default:
6346 			err = kIOReturnBadArgument;
6347 			break;
6348 		}
6349 	}
6350 
6351 	if (structureOutputSize > UINT_MAX) {
6352 		structureOutputSize = 0;
6353 		err = kIOReturnBadArgument;
6354 	}
6355 
6356 	args->structureOutputSize = ((typeof(args->structureOutputSize))structureOutputSize);
6357 
6358 	return err;
6359 }
6360 
6361 IOReturn
registerFilterCallbacks(const struct io_filter_callbacks * callbacks,size_t size)6362 IOUserClient::registerFilterCallbacks(const struct io_filter_callbacks *callbacks, size_t size)
6363 {
6364 	if (size < sizeof(*callbacks)) {
6365 		return kIOReturnBadArgument;
6366 	}
6367 	if (!OSCompareAndSwapPtr(NULL, __DECONST(void *, callbacks), &gIOUCFilterCallbacks)) {
6368 		return kIOReturnBusy;
6369 	}
6370 	return kIOReturnSuccess;
6371 }
6372 
6373 #if __LP64__
6374 OSMetaClassDefineReservedUnused(IOUserClient, 0);
6375 OSMetaClassDefineReservedUnused(IOUserClient, 1);
6376 #else
6377 OSMetaClassDefineReservedUsed(IOUserClient, 0);
6378 OSMetaClassDefineReservedUsed(IOUserClient, 1);
6379 #endif
6380 OSMetaClassDefineReservedUnused(IOUserClient, 2);
6381 OSMetaClassDefineReservedUnused(IOUserClient, 3);
6382 OSMetaClassDefineReservedUnused(IOUserClient, 4);
6383 OSMetaClassDefineReservedUnused(IOUserClient, 5);
6384 OSMetaClassDefineReservedUnused(IOUserClient, 6);
6385 OSMetaClassDefineReservedUnused(IOUserClient, 7);
6386 OSMetaClassDefineReservedUnused(IOUserClient, 8);
6387 OSMetaClassDefineReservedUnused(IOUserClient, 9);
6388 OSMetaClassDefineReservedUnused(IOUserClient, 10);
6389 OSMetaClassDefineReservedUnused(IOUserClient, 11);
6390 OSMetaClassDefineReservedUnused(IOUserClient, 12);
6391 OSMetaClassDefineReservedUnused(IOUserClient, 13);
6392 OSMetaClassDefineReservedUnused(IOUserClient, 14);
6393 OSMetaClassDefineReservedUnused(IOUserClient, 15);
6394