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