]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOUserServer.cpp
52508a7611a58abd2984a027b12360c8948c5427
[apple/xnu.git] / iokit / Kernel / IOUserServer.cpp
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 #include <IOKit/IORPC.h>
30 #include <IOKit/IOKitServer.h>
31 #include <IOKit/IOKitKeysPrivate.h>
32 #include <IOKit/IOUserClient.h>
33 #include <IOKit/IOService.h>
34 #include <IOKit/IORegistryEntry.h>
35 #include <IOKit/IOCatalogue.h>
36 #include <IOKit/IOMemoryDescriptor.h>
37 #include <IOKit/IOBufferMemoryDescriptor.h>
38 #include <IOKit/IOLib.h>
39 #include <IOKit/IOBSD.h>
40 #include <IOKit/system.h>
41 #include <IOKit/IOUserServer.h>
42 #include <IOKit/IOInterruptEventSource.h>
43 #include <IOKit/IOTimerEventSource.h>
44 #include <IOKit/pwr_mgt/RootDomain.h>
45 #include <libkern/c++/OSKext.h>
46 #include <libkern/OSDebug.h>
47 #include <libkern/Block.h>
48 #include <sys/proc.h>
49 #include "IOKitKernelInternal.h"
50
51 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
52
53 #include <DriverKit/IODispatchQueue.h>
54 #include <DriverKit/OSObject.h>
55 #include <DriverKit/OSAction.h>
56 #include <DriverKit/IODispatchSource.h>
57 #include <DriverKit/IOInterruptDispatchSource.h>
58 #include <DriverKit/IOService.h>
59 #include <DriverKit/IOMemoryDescriptor.h>
60 #include <DriverKit/IOBufferMemoryDescriptor.h>
61 #include <DriverKit/IOMemoryMap.h>
62 #include <DriverKit/IODataQueueDispatchSource.h>
63 #include <DriverKit/IOServiceNotificationDispatchSource.h>
64 #include <DriverKit/IOUserServer.h>
65
66 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
67
68 #include <System/IODataQueueDispatchSourceShared.h>
69
70 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
71
72 SInt64 gIODKDebug = kIODKEnable;
73
74 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
75
76 struct IOPStrings;
77
78 class OSUserMetaClass : public OSObject
79 {
80 OSDeclareDefaultStructors(OSUserMetaClass);
81 public:
82 const OSSymbol * name;
83 const OSMetaClass * meta;
84 OSUserMetaClass * superMeta;
85
86 queue_chain_t link;
87
88 OSClassDescription * description;
89 IOPStrings * queueNames;
90 uint32_t methodCount;
91 uint64_t * methods;
92
93 virtual void free() override;
94 virtual kern_return_t Dispatch(const IORPC rpc) APPLE_KEXT_OVERRIDE;
95 };
96 OSDefineMetaClassAndStructors(OSUserMetaClass, OSObject);
97
98 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
99
100 class IOUserService : public IOService
101 {
102 friend class IOService;
103
104 OSDeclareDefaultStructors(IOUserService)
105
106 virtual bool
107 start(IOService * provider) APPLE_KEXT_OVERRIDE;
108 };
109
110 OSDefineMetaClassAndStructors(IOUserService, IOService)
111
112 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
113
114 class IOUserUserClient : public IOUserClient
115 {
116 OSDeclareDefaultStructors(IOUserUserClient);
117 public:
118 task_t fTask;
119
120 IOReturn setTask(task_t task);
121 virtual void stop(IOService * provider) APPLE_KEXT_OVERRIDE;
122 virtual IOReturn clientClose(void) APPLE_KEXT_OVERRIDE;
123 virtual IOReturn setProperties(OSObject * properties) APPLE_KEXT_OVERRIDE;
124 virtual IOReturn externalMethod(uint32_t selector, IOExternalMethodArguments * args,
125 IOExternalMethodDispatch * dispatch, OSObject * target, void * reference) APPLE_KEXT_OVERRIDE;
126 virtual IOReturn clientMemoryForType(UInt32 type,
127 IOOptionBits * options,
128 IOMemoryDescriptor ** memory) APPLE_KEXT_OVERRIDE;
129 };
130
131
132 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
133
134
135 bool
136 IOUserService::start(IOService * provider)
137 {
138 bool ok = true;
139 IOReturn ret;
140
141 ret = Start(provider);
142 if (kIOReturnSuccess != ret) {
143 return false;
144 }
145
146 return ok;
147 }
148
149 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
150
151 #undef super
152
153 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
154
155 struct IODispatchQueue_IVars {
156 IOUserServer * userServer;
157 IODispatchQueue * queue;
158 queue_chain_t link;
159 uint64_t tid;
160
161 mach_port_t serverPort;
162 };
163
164 struct OSAction_IVars {
165 OSObject * target;
166 uint64_t targetmsgid;
167 uint64_t msgid;
168 OSActionAbortedHandler abortedHandler;
169 size_t referenceSize;
170 void * reference[0];
171 };
172
173 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
174
175 kern_return_t
176 IMPL(IOService, GetRegistryEntryID)
177 {
178 IOReturn ret = kIOReturnSuccess;
179
180 *registryEntryID = getRegistryEntryID();
181
182 return ret;
183 }
184
185 kern_return_t
186 IMPL(IOService, SetName)
187 {
188 IOReturn ret = kIOReturnSuccess;
189
190 setName(name);
191
192 return ret;
193 }
194
195 kern_return_t
196 IMPL(IOService, Start)
197 {
198 IOReturn ret = kIOReturnSuccess;
199 return ret;
200 }
201
202 kern_return_t
203 IMPL(IOService, RegisterService)
204 {
205 IOReturn ret = kIOReturnSuccess;
206
207 registerService();
208
209 return ret;
210 }
211
212 kern_return_t
213 IMPL(IOService, CopyDispatchQueue)
214 {
215 IODispatchQueue * result;
216 IOService * service;
217 IOReturn ret;
218 uint32_t index;
219
220 ret = kIOReturnNotFound;
221 index = -1U;
222 if (!strcmp("Default", name)) {
223 index = 0;
224 } else if (reserved->uvars->userMeta
225 && reserved->uvars->userMeta->queueNames) {
226 index = reserved->uvars->userServer->stringArrayIndex(reserved->uvars->userMeta->queueNames, name);
227 if (index != -1U) {
228 index++;
229 }
230 }
231 if (index == -1U) {
232 if ((service = getProvider())) {
233 ret = service->CopyDispatchQueue(name, queue);
234 }
235 } else {
236 result = reserved->uvars->queueArray[index];
237 if (result) {
238 result->retain();
239 *queue = result;
240 ret = kIOReturnSuccess;
241 }
242 }
243
244 return ret;
245 }
246
247 kern_return_t
248 IMPL(IOService, SetDispatchQueue)
249 {
250 IOReturn ret = kIOReturnSuccess;
251 uint32_t index;
252
253 if (kIODKLogSetup & gIODKDebug) {
254 DKLOG(DKS "::SetDispatchQueue(%s)\n", DKN(this), name);
255 }
256 queue->ivars->userServer = reserved->uvars->userServer;
257 index = -1U;
258 if (!strcmp("Default", name)) {
259 index = 0;
260 } else if (reserved->uvars->userMeta
261 && reserved->uvars->userMeta->queueNames) {
262 index = reserved->uvars->userServer->stringArrayIndex(reserved->uvars->userMeta->queueNames, name);
263 if (index != -1U) {
264 index++;
265 }
266 }
267 if (index == -1U) {
268 ret = kIOReturnBadArgument;
269 } else {
270 reserved->uvars->queueArray[index] = queue;
271 queue->retain();
272 }
273
274 return ret;
275 }
276
277 kern_return_t
278 IMPL(IOService, SetProperties)
279 {
280 IOUserServer * us;
281 OSDictionary * dict;
282 IOReturn ret;
283
284 ret = setProperties(properties);
285
286 if (kIOReturnUnsupported == ret) {
287 dict = OSDynamicCast(OSDictionary, properties);
288 us = (typeof(us))thread_iokit_tls_get(0);
289 if (dict && reserved->uvars && (reserved->uvars->userServer == us)) {
290 ret = runPropertyActionBlock(^IOReturn (void) {
291 OSDictionary * userProps;
292 IOReturn ret;
293
294 userProps = OSDynamicCast(OSDictionary, getProperty(gIOUserServicePropertiesKey));
295 if (userProps) {
296 userProps = (typeof(userProps))userProps->copyCollection();
297 } else {
298 userProps = OSDictionary::withCapacity(4);
299 }
300 if (!userProps) {
301 ret = kIOReturnNoMemory;
302 } else {
303 bool ok = userProps->merge(dict);
304 if (ok) {
305 ok = setProperty(gIOUserServicePropertiesKey, userProps);
306 }
307 OSSafeReleaseNULL(userProps);
308 ret = ok ? kIOReturnSuccess : kIOReturnNotWritable;
309 }
310 return ret;
311 });
312 }
313 }
314
315 return ret;
316 }
317
318 kern_return_t
319 IMPL(IOService, CopyProperties)
320 {
321 IOReturn ret = kIOReturnSuccess;
322 *properties = dictionaryWithProperties();
323 return ret;
324 }
325
326 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
327
328 kern_return_t
329 IMPL(IOMemoryDescriptor, _CopyState)
330 {
331 IOReturn ret;
332
333 state->length = _length;
334 state->options = _flags;
335
336 ret = kIOReturnSuccess;
337
338 return ret;
339 }
340
341 kern_return_t
342 IOMemoryDescriptor::GetLength(uint64_t * returnLength)
343 {
344 *returnLength = getLength();
345
346 return kIOReturnSuccess;
347 }
348
349 kern_return_t
350 IMPL(IOMemoryDescriptor, CreateMapping)
351 {
352 IOReturn ret;
353 IOMemoryMap * resultMap;
354 IOOptionBits koptions;
355 mach_vm_address_t atAddress;
356
357 ret = kIOReturnSuccess;
358 koptions = 0;
359 resultMap = NULL;
360
361 if (kIOMemoryMapFixedAddress & options) {
362 atAddress = address;
363 koptions = 0;
364 } else {
365 atAddress = 0;
366 koptions |= kIOMapAnywhere;
367 }
368
369 if (kIOMemoryMapReadOnly & options || (kIODirectionOut == getDirection())) {
370 if (!reserved || (current_task() != reserved->creator)) {
371 koptions |= kIOMapReadOnly;
372 }
373 }
374
375 switch (0xFF00 & options) {
376 case kIOMemoryMapCacheModeDefault:
377 koptions |= kIOMapDefaultCache;
378 break;
379 case kIOMemoryMapCacheModeInhibit:
380 koptions |= kIOMapInhibitCache;
381 break;
382 case kIOMemoryMapCacheModeCopyback:
383 koptions |= kIOMapCopybackCache;
384 break;
385 case kIOMemoryMapCacheModeWriteThrough:
386 koptions |= kIOMapWriteThruCache;
387 break;
388 default:
389 ret = kIOReturnBadArgument;
390 }
391
392 if (kIOReturnSuccess == ret) {
393 resultMap = createMappingInTask(current_task(), atAddress, koptions, offset, length);
394 if (!resultMap) {
395 ret = kIOReturnError;
396 }
397 }
398
399 *map = resultMap;
400
401 return ret;
402 }
403
404 kern_return_t
405 IMPL(IOMemoryDescriptor, PrepareForDMA)
406 {
407 IOReturn ret;
408 uint32_t idx, count;
409 uint64_t sumLength;
410 uint64_t lflags;
411
412 if (!device) {
413 return kIOReturnBadArgument;
414 }
415
416 count = *segmentsCount;
417 sumLength = 0;
418 for (idx = 0; idx < count; idx++) {
419 #ifdef __LP64__
420 segments[idx].address = getPhysicalSegment(offset, &segments[idx].length);
421 #else
422 segments[idx].address = 0;
423 #endif
424 if (!segments[idx].address) {
425 break;
426 }
427 sumLength += segments[idx].length;
428 offset += segments[idx].length;
429 }
430 *returnLength = sumLength;
431 *segmentsCount = idx;
432
433 // !!translate flags
434 lflags = 0;
435 if (kIODirectionOut & _flags) {
436 lflags |= kIOMemoryDirectionOut;
437 }
438 if (kIODirectionIn & _flags) {
439 lflags |= kIOMemoryDirectionIn;
440 }
441
442 *flags = lflags;
443 ret = kIOReturnSuccess;
444
445 return ret;
446 }
447
448 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
449
450 kern_return_t
451 IMPL(IOMemoryMap, _CopyState)
452 {
453 IOReturn ret;
454
455 state->offset = fOffset;
456 state->length = getLength();
457 state->address = getAddress();
458 state->options = getMapOptions();
459
460 ret = kIOReturnSuccess;
461
462 return ret;
463 }
464
465 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
466
467 kern_return_t
468 IMPL(IOBufferMemoryDescriptor, Create)
469 {
470 IOReturn ret;
471 IOBufferMemoryDescriptor * bmd;
472 IOMemoryDescriptorReserved * reserved;
473
474 if (options & ~((uint64_t) kIOMemoryDirectionOutIn)) {
475 // no other options currently defined
476 return kIOReturnBadArgument;
477 }
478 options &= kIOMemoryDirectionOutIn;
479 options |= kIOMemoryKernelUserShared;
480 bmd = IOBufferMemoryDescriptor::inTaskWithOptions(
481 kernel_task, options, capacity, alignment);
482
483 *memory = bmd;
484
485 if (!bmd) {
486 return kIOReturnNoMemory;
487 }
488
489 reserved = bmd->getKernelReserved();
490 reserved->creator = current_task();
491 task_reference(reserved->creator);
492
493 ret = kIOReturnSuccess;
494
495 return ret;
496 }
497
498 kern_return_t
499 IMPL(IOBufferMemoryDescriptor, SetLength)
500 {
501 setLength(length);
502 return kIOReturnSuccess;
503 }
504
505 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
506
507 kern_return_t
508 OSAction::Create(OSAction_Create_Args)
509 {
510 kern_return_t ret;
511 ret = OSAction::Create_Call(target, targetmsgid, msgid, referenceSize, action);
512 return ret;
513 }
514
515 kern_return_t
516 IMPL(OSAction, Create)
517 {
518 OSAction * inst;
519 vm_size_t allocsize;
520
521 if (os_add_overflow(referenceSize, sizeof(OSAction_IVars), &allocsize)) {
522 return kIOReturnBadArgument;
523 }
524 inst = OSTypeAlloc(OSAction);
525 if (!inst) {
526 return kIOReturnNoMemory;
527 }
528 inst->ivars = (typeof(inst->ivars))(uintptr_t) IONewZero(uint8_t, allocsize);
529 if (!inst->ivars) {
530 inst->release();
531 return kIOReturnNoMemory;
532 }
533 target->retain();
534 inst->ivars->target = target;
535 inst->ivars->targetmsgid = targetmsgid;
536 inst->ivars->msgid = msgid;
537 inst->ivars->referenceSize = referenceSize;
538
539 *action = inst;
540
541 return kIOReturnSuccess;
542 }
543
544 void
545 OSAction::free()
546 {
547 if (ivars) {
548 if (ivars->abortedHandler) {
549 Block_release(ivars->abortedHandler);
550 ivars->abortedHandler = NULL;
551 }
552 OSSafeReleaseNULL(ivars->target);
553 IOSafeDeleteNULL(ivars, uint8_t, ivars->referenceSize + sizeof(OSAction_IVars));
554 }
555 return super::free();
556 }
557
558 void *
559 OSAction::GetReference()
560 {
561 assert(ivars && ivars->referenceSize);
562 return &ivars->reference[0];
563 }
564
565 kern_return_t
566 OSAction::SetAbortedHandler(OSActionAbortedHandler handler)
567 {
568 ivars->abortedHandler = Block_copy(handler);
569 return kIOReturnSuccess;
570 }
571
572 void
573 OSAction::Aborted_Impl(void)
574 {
575 if (ivars->abortedHandler) {
576 ivars->abortedHandler();
577 }
578 }
579
580 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
581
582 struct IODispatchSource_IVars {
583 queue_chain_t link;
584 IODispatchSource * source;
585 IOUserServer * server;
586 IODispatchQueue_IVars * queue;
587 bool enabled;
588 };
589
590 bool
591 IODispatchSource::init()
592 {
593 if (!super::init()) {
594 return false;
595 }
596
597 ivars = IONewZero(IODispatchSource_IVars, 1);
598
599 ivars->source = this;
600
601 return true;
602 }
603
604 void
605 IODispatchSource::free()
606 {
607 IOSafeDeleteNULL(ivars, IODispatchSource_IVars, 1);
608 super::free();
609 }
610
611 kern_return_t
612 IMPL(IODispatchSource, SetEnable)
613 {
614 return SetEnableWithCompletion(enable, NULL);
615 }
616
617 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
618
619 struct IOInterruptDispatchSource_IVars {
620 IOService * provider;
621 uint32_t intIndex;
622 IOSimpleLock * lock;
623 thread_t waiter;
624 uint64_t count;
625 uint64_t time;
626 OSAction * action;
627 bool enable;
628 };
629
630 static void
631 IOInterruptDispatchSourceInterrupt(OSObject * target, void * refCon,
632 IOService * nub, int source )
633 {
634 IOInterruptDispatchSource_IVars * ivars = (typeof(ivars))refCon;
635 IOInterruptState is;
636
637 is = IOSimpleLockLockDisableInterrupt(ivars->lock);
638 ivars->count++;
639 if (ivars->waiter) {
640 ivars->time = mach_absolute_time();
641 thread_wakeup_thread((event_t) ivars, ivars->waiter);
642 ivars->waiter = NULL;
643 }
644 IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
645 }
646
647 kern_return_t
648 IMPL(IOInterruptDispatchSource, Create)
649 {
650 IOReturn ret;
651 IOInterruptDispatchSource * inst;
652
653 inst = OSTypeAlloc(IOInterruptDispatchSource);
654 if (!inst->init()) {
655 inst->free();
656 return kIOReturnNoMemory;
657 }
658
659 inst->ivars->lock = IOSimpleLockAlloc();
660
661 ret = provider->registerInterrupt(index, inst, IOInterruptDispatchSourceInterrupt, inst->ivars);
662 if (kIOReturnSuccess == ret) {
663 inst->ivars->intIndex = index;
664 inst->ivars->provider = provider;
665 *source = inst;
666 }
667 return ret;
668 }
669
670 bool
671 IOInterruptDispatchSource::init()
672 {
673 if (!super::init()) {
674 return false;
675 }
676 ivars = IONewZero(IOInterruptDispatchSource_IVars, 1);
677 if (!ivars) {
678 return false;
679 }
680
681 return true;
682 }
683
684 void
685 IOInterruptDispatchSource::free()
686 {
687 IOReturn ret;
688
689 if (ivars && ivars->provider) {
690 ret = ivars->provider->unregisterInterrupt(ivars->intIndex);
691 assert(kIOReturnSuccess == ret);
692 }
693
694 if (ivars && ivars->lock) {
695 IOSimpleLockFree(ivars->lock);
696 }
697
698 IOSafeDeleteNULL(ivars, IOInterruptDispatchSource_IVars, 1);
699
700 super::free();
701 }
702
703 kern_return_t
704 IMPL(IOInterruptDispatchSource, SetHandler)
705 {
706 IOReturn ret;
707 OSAction * oldAction;
708
709 oldAction = (typeof(oldAction))ivars->action;
710 if (oldAction && OSCompareAndSwapPtr(oldAction, NULL, &ivars->action)) {
711 oldAction->release();
712 }
713 action->retain();
714 ivars->action = action;
715
716 ret = kIOReturnSuccess;
717
718 return ret;
719 }
720
721 kern_return_t
722 IMPL(IOInterruptDispatchSource, SetEnableWithCompletion)
723 {
724 IOReturn ret;
725 IOInterruptState is;
726
727 if (enable == ivars->enable) {
728 return kIOReturnSuccess;
729 }
730
731 if (enable) {
732 is = IOSimpleLockLockDisableInterrupt(ivars->lock);
733 ivars->enable = enable;
734 IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
735 ret = ivars->provider->enableInterrupt(ivars->intIndex);
736 } else {
737 ret = ivars->provider->disableInterrupt(ivars->intIndex);
738 is = IOSimpleLockLockDisableInterrupt(ivars->lock);
739 ivars->enable = enable;
740 IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
741 }
742
743 return ret;
744 }
745
746 kern_return_t
747 IMPL(IOInterruptDispatchSource, Cancel)
748 {
749 return kIOReturnUnsupported;
750 }
751
752 kern_return_t
753 IMPL(IOInterruptDispatchSource, CheckForWork)
754 {
755 IOReturn ret = kIOReturnNotReady;
756 IOInterruptState is;
757 wait_result_t waitResult;
758 uint64_t icount;
759 uint64_t itime;
760 thread_t self;
761
762 self = current_thread();
763 icount = 0;
764 do {
765 is = IOSimpleLockLockDisableInterrupt(ivars->lock);
766 if ((icount = ivars->count)) {
767 itime = ivars->time;
768 ivars->count = 0;
769 waitResult = THREAD_AWAKENED;
770 } else if (synchronous) {
771 assert(NULL == ivars->waiter);
772 ivars->waiter = self;
773 waitResult = assert_wait((event_t) ivars, THREAD_INTERRUPTIBLE);
774 }
775 IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
776 if (synchronous && (waitResult == THREAD_WAITING)) {
777 waitResult = thread_block(THREAD_CONTINUE_NULL);
778 if (THREAD_INTERRUPTED == waitResult) {
779 break;
780 }
781 }
782 } while (synchronous && !icount);
783
784 if (icount && ivars->action) {
785 ret = InterruptOccurred(rpc, ivars->action, icount, itime);
786 }
787
788 return ret;
789 }
790
791 void
792 IMPL(IOInterruptDispatchSource, InterruptOccurred)
793 {
794 }
795
796 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
797
798 enum {
799 kIOServiceNotificationTypeCount = kIOServiceNotificationTypeLast + 1,
800 };
801
802 struct IOServiceNotificationDispatchSource_IVars {
803 OSObject * serverName;
804 OSAction * action;
805 IOLock * lock;
806 IONotifier * notifier;
807 OSDictionary * interestNotifiers;
808 OSArray * pending[kIOServiceNotificationTypeCount];
809 bool enable;
810 };
811
812 kern_return_t
813 IMPL(IOServiceNotificationDispatchSource, Create)
814 {
815 IOUserServer * us;
816 IOReturn ret;
817 IOServiceNotificationDispatchSource * inst;
818
819 inst = OSTypeAlloc(IOServiceNotificationDispatchSource);
820 if (!inst->init()) {
821 OSSafeReleaseNULL(inst);
822 return kIOReturnNoMemory;
823 }
824
825 us = (typeof(us))thread_iokit_tls_get(0);
826 assert(OSDynamicCast(IOUserServer, us));
827 if (!us) {
828 OSSafeReleaseNULL(inst);
829 return kIOReturnError;
830 }
831 inst->ivars->serverName = us->copyProperty(gIOUserServerNameKey);
832 if (!inst->ivars->serverName) {
833 OSSafeReleaseNULL(inst);
834 return kIOReturnNoMemory;
835 }
836
837 inst->ivars->lock = IOLockAlloc();
838 if (!inst->ivars->lock) {
839 OSSafeReleaseNULL(inst);
840 return kIOReturnNoMemory;
841 }
842 for (uint32_t idx = 0; idx < kIOServiceNotificationTypeCount; idx++) {
843 inst->ivars->pending[idx] = OSArray::withCapacity(4);
844 if (!inst->ivars->pending[idx]) {
845 OSSafeReleaseNULL(inst);
846 return kIOReturnNoMemory;
847 }
848 }
849 inst->ivars->interestNotifiers = OSDictionary::withCapacity(4);
850 if (!inst->ivars->interestNotifiers) {
851 OSSafeReleaseNULL(inst);
852 return kIOReturnNoMemory;
853 }
854
855 inst->ivars->notifier = IOService::addMatchingNotification(gIOMatchedNotification, matching, 0 /*priority*/,
856 ^bool (IOService * newService, IONotifier * notifier) {
857 bool notifyReady = false;
858 IONotifier * interest;
859 OSObject * serverName;
860 bool okToUse;
861
862 serverName = newService->copyProperty(gIOUserServerNameKey);
863 okToUse = (serverName && inst->ivars->serverName->isEqualTo(serverName));
864 OSSafeReleaseNULL(serverName);
865 if (!okToUse) {
866 return false;
867 }
868
869 IOLockLock(inst->ivars->lock);
870 notifyReady = (0 == inst->ivars->pending[kIOServiceNotificationTypeMatched]->getCount());
871 inst->ivars->pending[kIOServiceNotificationTypeMatched]->setObject(newService);
872 IOLockUnlock(inst->ivars->lock);
873
874 interest = newService->registerInterest(gIOGeneralInterest,
875 ^IOReturn (uint32_t messageType, IOService * provider,
876 void * messageArgument, size_t argSize) {
877 IONotifier * interest;
878 bool notifyReady = false;
879
880 switch (messageType) {
881 case kIOMessageServiceIsTerminated:
882 IOLockLock(inst->ivars->lock);
883 notifyReady = (0 == inst->ivars->pending[kIOServiceNotificationTypeTerminated]->getCount());
884 inst->ivars->pending[kIOServiceNotificationTypeTerminated]->setObject(provider);
885 interest = (typeof(interest))inst->ivars->interestNotifiers->getObject((const OSSymbol *) newService);
886 assert(interest);
887 interest->remove();
888 inst->ivars->interestNotifiers->removeObject((const OSSymbol *) newService);
889 IOLockUnlock(inst->ivars->lock);
890 break;
891 default:
892 break;
893 }
894 if (notifyReady && inst->ivars->action) {
895 inst->ServiceNotificationReady(inst->ivars->action);
896 }
897 return kIOReturnSuccess;
898 });
899 if (interest) {
900 IOLockLock(inst->ivars->lock);
901 inst->ivars->interestNotifiers->setObject((const OSSymbol *) newService, interest);
902 IOLockUnlock(inst->ivars->lock);
903 }
904 if (notifyReady) {
905 if (inst->ivars->action) {
906 inst->ServiceNotificationReady(inst->ivars->action);
907 }
908 }
909 return false;
910 });
911
912 if (!inst->ivars->notifier) {
913 OSSafeReleaseNULL(inst);
914 ret = kIOReturnError;
915 }
916
917 *notification = inst;
918 ret = kIOReturnSuccess;
919
920 return ret;
921 }
922
923 kern_return_t
924 IMPL(IOServiceNotificationDispatchSource, CopyNextNotification)
925 {
926 IOService * next;
927 uint32_t idx;
928
929 IOLockLock(ivars->lock);
930 for (idx = 0; idx < kIOServiceNotificationTypeCount; idx++) {
931 next = (IOService *) ivars->pending[idx]->getObject(0);
932 if (next) {
933 next->retain();
934 ivars->pending[idx]->removeObject(0);
935 break;
936 }
937 }
938 IOLockUnlock(ivars->lock);
939
940 if (idx == kIOServiceNotificationTypeCount) {
941 idx = kIOServiceNotificationTypeNone;
942 }
943 *type = idx;
944 *service = next;
945 *options = 0;
946
947 return kIOReturnSuccess;
948 }
949
950 bool
951 IOServiceNotificationDispatchSource::init()
952 {
953 if (!super::init()) {
954 return false;
955 }
956 ivars = IONewZero(IOServiceNotificationDispatchSource_IVars, 1);
957 if (!ivars) {
958 return false;
959 }
960
961 return true;
962 }
963
964 void
965 IOServiceNotificationDispatchSource::free()
966 {
967 if (ivars) {
968 OSSafeReleaseNULL(ivars->serverName);
969 if (ivars->interestNotifiers) {
970 ivars->interestNotifiers->iterateObjects(^bool (const OSSymbol * key, OSObject * object) {
971 IONotifier * interest = (typeof(interest))object;
972 interest->remove();
973 return false;
974 });
975 OSSafeReleaseNULL(ivars->interestNotifiers);
976 }
977 for (uint32_t idx = 0; idx < kIOServiceNotificationTypeCount; idx++) {
978 OSSafeReleaseNULL(ivars->pending[idx]);
979 }
980 if (ivars->lock) {
981 IOLockFree(ivars->lock);
982 ivars->lock = NULL;
983 }
984 if (ivars->notifier) {
985 ivars->notifier->remove();
986 ivars->notifier = NULL;
987 }
988 IOSafeDeleteNULL(ivars, IOServiceNotificationDispatchSource_IVars, 1);
989 }
990
991 super::free();
992 }
993
994 kern_return_t
995 IMPL(IOServiceNotificationDispatchSource, SetHandler)
996 {
997 IOReturn ret;
998 bool notifyReady;
999
1000 notifyReady = false;
1001
1002 IOLockLock(ivars->lock);
1003 OSSafeReleaseNULL(ivars->action);
1004 action->retain();
1005 ivars->action = action;
1006 if (action) {
1007 for (uint32_t idx = 0; idx < kIOServiceNotificationTypeCount; idx++) {
1008 notifyReady = (ivars->pending[idx]->getCount());
1009 if (notifyReady) {
1010 break;
1011 }
1012 }
1013 }
1014 IOLockUnlock(ivars->lock);
1015
1016 if (notifyReady) {
1017 ServiceNotificationReady(action);
1018 }
1019 ret = kIOReturnSuccess;
1020
1021 return ret;
1022 }
1023
1024 kern_return_t
1025 IMPL(IOServiceNotificationDispatchSource, SetEnableWithCompletion)
1026 {
1027 if (enable == ivars->enable) {
1028 return kIOReturnSuccess;
1029 }
1030
1031 IOLockLock(ivars->lock);
1032 ivars->enable = enable;
1033 IOLockUnlock(ivars->lock);
1034
1035 return kIOReturnSuccess;
1036 }
1037
1038 kern_return_t
1039 IMPL(IOServiceNotificationDispatchSource, Cancel)
1040 {
1041 return kIOReturnUnsupported;
1042 }
1043
1044 kern_return_t
1045 IMPL(IOServiceNotificationDispatchSource, CheckForWork)
1046 {
1047 return kIOReturnNotReady;
1048 }
1049
1050 kern_return_t
1051 IOServiceNotificationDispatchSource::DeliverNotifications(IOServiceNotificationBlock block)
1052 {
1053 return kIOReturnUnsupported;
1054 }
1055
1056 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1057
1058 kern_return_t
1059 IOUserServer::waitInterruptTrap(void * p1, void * p2, void * p3, void * p4, void * p5, void * p6)
1060 {
1061 IOReturn ret = kIOReturnBadArgument;
1062 IOInterruptState is;
1063 IOInterruptDispatchSource * interrupt;
1064 IOInterruptDispatchSource_IVars * ivars;
1065 IOInterruptDispatchSourcePayload payload;
1066
1067 wait_result_t waitResult;
1068 thread_t self;
1069
1070 OSObject * object;
1071
1072 object = iokit_lookup_object_with_port_name((mach_port_name_t)(uintptr_t)p1, IKOT_UEXT_OBJECT, current_task());
1073
1074 if (!object) {
1075 return kIOReturnBadArgument;
1076 }
1077 if (!(interrupt = OSDynamicCast(IOInterruptDispatchSource, object))) {
1078 ret = kIOReturnBadArgument;
1079 } else {
1080 self = current_thread();
1081 ivars = interrupt->ivars;
1082 payload.count = 0;
1083 do {
1084 is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1085 if ((payload.count = ivars->count)) {
1086 payload.time = ivars->time;
1087 ivars->count = 0;
1088 waitResult = THREAD_AWAKENED;
1089 } else {
1090 assert(NULL == ivars->waiter);
1091 ivars->waiter = self;
1092 waitResult = assert_wait((event_t) ivars, THREAD_INTERRUPTIBLE);
1093 }
1094 IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1095 if (waitResult == THREAD_WAITING) {
1096 waitResult = thread_block(THREAD_CONTINUE_NULL);
1097 if (THREAD_INTERRUPTED == waitResult) {
1098 break;
1099 }
1100 }
1101 } while (!payload.count);
1102 ret = (payload.count ? kIOReturnSuccess : kIOReturnAborted);
1103 }
1104
1105 if (kIOReturnSuccess == ret) {
1106 int copyerr = copyout(&payload, (user_addr_t) p2, sizeof(payload));
1107 if (copyerr) {
1108 ret = kIOReturnVMError;
1109 }
1110 }
1111
1112 object->release();
1113
1114 return ret;
1115 }
1116
1117 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1118
1119 kern_return_t
1120 IMPL(IOUserServer, Create)
1121 {
1122 IOReturn ret;
1123 IOUserServer * us;
1124 const OSSymbol * sym;
1125 OSNumber * serverTag;
1126 io_name_t rname;
1127
1128 us = (typeof(us))thread_iokit_tls_get(0);
1129 assert(OSDynamicCast(IOUserServer, us));
1130 if (kIODKLogSetup & gIODKDebug) {
1131 DKLOG(DKS "::Create(" DKS ") %p\n", DKN(us), name, tag, us);
1132 }
1133 if (!us) {
1134 return kIOReturnError;
1135 }
1136
1137 sym = OSSymbol::withCString(name);
1138 serverTag = OSNumber::withNumber(tag, 64);
1139
1140 us->setProperty(gIOUserServerNameKey, (OSObject *) sym);
1141 us->setProperty(gIOUserServerTagKey, serverTag);
1142
1143 serverTag->release();
1144 OSSafeReleaseNULL(sym);
1145
1146 snprintf(rname, sizeof(rname), "IOUserServer(%s-0x%qx)", name, tag);
1147 us->setName(rname);
1148
1149 us->retain();
1150 *server = us;
1151 ret = kIOReturnSuccess;
1152
1153 return ret;
1154 }
1155
1156 kern_return_t
1157 IMPL(IOUserServer, Exit)
1158 {
1159 return kIOReturnUnsupported;
1160 }
1161
1162 kern_return_t
1163 IMPL(IOUserServer, LoadModule)
1164 {
1165 return kIOReturnUnsupported;
1166 }
1167
1168
1169 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1170
1171 kern_return_t
1172 IMPL(IODispatchQueue, Create)
1173 {
1174 IODispatchQueue * result;
1175 IOUserServer * us;
1176
1177 result = OSTypeAlloc(IODispatchQueue);
1178 if (!result) {
1179 return kIOReturnNoMemory;
1180 }
1181 if (!result->init()) {
1182 return kIOReturnNoMemory;
1183 }
1184
1185 *queue = result;
1186
1187 if (!strcmp("Root", name)) {
1188 us = (typeof(us))thread_iokit_tls_get(0);
1189 assert(OSDynamicCast(IOUserServer, us));
1190 us->setRootQueue(result);
1191 }
1192
1193 if (kIODKLogSetup & gIODKDebug) {
1194 DKLOG("IODispatchQueue::Create %s %p\n", name, result);
1195 }
1196
1197 return kIOReturnSuccess;
1198 }
1199
1200 kern_return_t
1201 IMPL(IODispatchQueue, SetPort)
1202 {
1203 if (MACH_PORT_NULL != ivars->serverPort) {
1204 return kIOReturnNotReady;
1205 }
1206
1207 ivars->serverPort = port;
1208 return kIOReturnSuccess;
1209 }
1210
1211 bool
1212 IODispatchQueue::init()
1213 {
1214 ivars = IONewZero(IODispatchQueue_IVars, 1);
1215 if (!ivars) {
1216 return false;
1217 }
1218 ivars->queue = this;
1219
1220 return true;
1221 }
1222
1223 void
1224 IODispatchQueue::free()
1225 {
1226 if (ivars && ivars->serverPort) {
1227 ipc_port_release_send(ivars->serverPort);
1228 ivars->serverPort = MACH_PORT_NULL;
1229 }
1230 IOSafeDeleteNULL(ivars, IODispatchQueue_IVars, 1);
1231 super::free();
1232 }
1233
1234 bool
1235 IODispatchQueue::OnQueue()
1236 {
1237 return false;
1238 }
1239
1240 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1241
1242
1243 kern_return_t
1244 OSMetaClassBase::Dispatch(IORPC rpc)
1245 {
1246 return kIOReturnUnsupported;
1247 }
1248
1249 kern_return_t
1250 OSMetaClassBase::Invoke(IORPC rpc)
1251 {
1252 IOReturn ret = kIOReturnUnsupported;
1253 OSMetaClassBase * object;
1254 OSAction * action;
1255 IOService * service;
1256 IOUserServer * us;
1257 IORPCMessage * message;
1258
1259 assert(rpc.sendSize >= (sizeof(IORPCMessageMach) + sizeof(IORPCMessage)));
1260 message = IORPCMessageFromMach(rpc.message, false);
1261 if (!message) {
1262 return kIOReturnIPCError;
1263 }
1264 message->flags |= kIORPCMessageKernel;
1265
1266 us = NULL;
1267 if (!(kIORPCMessageLocalHost & message->flags)) {
1268 us = OSDynamicCast(IOUserServer, this);
1269 if (!us) {
1270 if ((action = OSDynamicCast(OSAction, this))) {
1271 object = IOUserServer::target(action, message);
1272 } else {
1273 object = this;
1274 }
1275 if ((service = OSDynamicCast(IOService, object))
1276 && service->reserved->uvars) {
1277 // xxx other classes
1278 us = service->reserved->uvars->userServer;
1279 }
1280 }
1281 }
1282 if (us) {
1283 message->flags |= kIORPCMessageRemote;
1284 ret = us->rpc(rpc);
1285 if (kIOReturnSuccess != ret) {
1286 if (kIODKLogIPC & gIODKDebug) {
1287 DKLOG("OSMetaClassBase::Invoke user 0x%x\n", ret);
1288 }
1289 }
1290 } else {
1291 if (kIODKLogIPC & gIODKDebug) {
1292 DKLOG("OSMetaClassBase::Invoke kernel %s 0x%qx\n", getMetaClass()->getClassName(), message->msgid);
1293 }
1294 ret = Dispatch(rpc);
1295 }
1296
1297 return ret;
1298 }
1299
1300 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1301
1302 struct IOPStrings {
1303 uint32_t dataSize;
1304 uint32_t count;
1305 const char strings[0];
1306 };
1307
1308 kern_return_t
1309 OSUserMetaClass::Dispatch(IORPC rpc)
1310 {
1311 if (meta) {
1312 return const_cast<OSMetaClass *>(meta)->Dispatch(rpc);
1313 } else {
1314 return kIOReturnUnsupported;
1315 }
1316 }
1317
1318 void
1319 OSUserMetaClass::free()
1320 {
1321 if (queueNames) {
1322 IOFree(queueNames, sizeof(IOPStrings) + queueNames->dataSize * sizeof(char));
1323 queueNames = NULL;
1324 }
1325 if (description) {
1326 IOFree(description, description->descriptionSize);
1327 description = NULL;
1328 }
1329 IOSafeDeleteNULL(methods, uint64_t, 2 * methodCount);
1330 if (meta) {
1331 meta->releaseMetaClass();
1332 }
1333 if (name) {
1334 name->release();
1335 }
1336 OSObject::free();
1337 }
1338
1339 /*
1340 * Sets the loadTag of the associated OSKext
1341 * in the dext task.
1342 * NOTE: different instances of the same OSKext
1343 * (so same BounleID but different tasks)
1344 * will have the same loadTag.
1345 */
1346 void
1347 IOUserServer::setTaskLoadTag(OSKext *kext)
1348 {
1349 task_t owningTask;
1350 uint32_t loadTag, prev_taskloadTag;
1351
1352 owningTask = this->fOwningTask;
1353 if (!owningTask) {
1354 printf("%s: fOwningTask not found\n", __FUNCTION__);
1355 return;
1356 }
1357
1358 loadTag = kext->getLoadTag();
1359 prev_taskloadTag = set_task_loadTag(owningTask, loadTag);
1360 if (prev_taskloadTag) {
1361 printf("%s: found the task loadTag already set to %u (set to %u)\n",
1362 __FUNCTION__, prev_taskloadTag, loadTag);
1363 }
1364 }
1365
1366 /*
1367 * Sets the OSKext uuid as the uuid of the userspace
1368 * dext executable.
1369 */
1370 void
1371 IOUserServer::setDriverKitUUID(OSKext *kext)
1372 {
1373 task_t task;
1374 proc_t p;
1375 uuid_t p_uuid, k_uuid;
1376 OSData *k_data_uuid;
1377 OSData *new_uuid;
1378 uuid_string_t uuid_string = "";
1379
1380 task = this->fOwningTask;
1381 if (!task) {
1382 printf("%s: fOwningTask not found\n", __FUNCTION__);
1383 return;
1384 }
1385
1386 p = (proc_t)(get_bsdtask_info(task));
1387 if (!p) {
1388 printf("%s: proc not found\n", __FUNCTION__);
1389 return;
1390 }
1391 proc_getexecutableuuid(p, p_uuid, sizeof(p_uuid));
1392
1393 k_data_uuid = kext->copyUUID();
1394 if (k_data_uuid) {
1395 memcpy(&k_uuid, k_data_uuid->getBytesNoCopy(), sizeof(k_uuid));
1396 OSSafeReleaseNULL(k_data_uuid);
1397 if (uuid_compare(k_uuid, p_uuid) != 0) {
1398 printf("%s: uuid not matching\n", __FUNCTION__);
1399 }
1400 return;
1401 }
1402
1403 uuid_unparse(p_uuid, uuid_string);
1404 new_uuid = OSData::withBytes(p_uuid, sizeof(p_uuid));
1405 kext->setDriverKitUUID(new_uuid);
1406 }
1407
1408 bool
1409 IOUserServer::serviceMatchesCDHash(IOService *service)
1410 {
1411 OSObject *obj = NULL;
1412 bool result = false;
1413 OSString *requiredCDHashStr = NULL;
1414 const char *requiredCDHash = NULL;
1415 char taskCDHash[CS_CDHASH_LEN];
1416
1417 task_t owningTask = this->fOwningTask;
1418 if (!owningTask) {
1419 printf("%s: fOwningTask not found\n", __FUNCTION__);
1420 goto out;
1421 }
1422
1423 obj = service->copyProperty(gIOUserServerCDHashKey);
1424 requiredCDHashStr = OSDynamicCast(OSString, obj);
1425 if (!requiredCDHashStr) {
1426 printf("%s: required cdhash not found as property of personality\n", __FUNCTION__);
1427 goto out;
1428 }
1429
1430 requiredCDHash = requiredCDHashStr->getCStringNoCopy();
1431 if (!requiredCDHash) {
1432 printf("%s: required cdhash unable to be read as string\n", __FUNCTION__);
1433 goto out;
1434 }
1435
1436 if (strlen(requiredCDHash) != CS_CDHASH_LEN * 2) {
1437 printf("%s: required cdhash string has incorrect length\n", __FUNCTION__);
1438 goto out;
1439 }
1440
1441 get_task_cdhash(owningTask, taskCDHash);
1442 for (int i = 0; i < (int)CS_CDHASH_LEN * 2; i++) {
1443 uint8_t which = (i + 1) & 0x1; /* 1 for upper nibble, 0 for lower */
1444 uint8_t nibble = requiredCDHash[i];
1445 uint8_t byte = taskCDHash[i / 2];
1446 if ('0' <= nibble && nibble <= '9') {
1447 nibble -= '0';
1448 } else if ('a' <= nibble && nibble <= 'f') {
1449 nibble -= 'a' - 10;
1450 } else if ('A' <= nibble && nibble <= 'F') {
1451 nibble -= 'A' - 10;
1452 } else {
1453 printf("%s: required cdhash contains invalid token '%c'\n", __FUNCTION__, nibble);
1454 goto out;
1455 }
1456
1457 /*
1458 * Decide which half of the byte to compare
1459 */
1460 if (nibble != (which ? (byte >> 4) : (byte & 0x0f))) {
1461 printf("%s: required cdhash %s in personality does not match service\n", __FUNCTION__, requiredCDHash);
1462 goto out;
1463 }
1464 }
1465
1466 result = true;
1467 out:
1468 OSSafeReleaseNULL(obj);
1469 return result;
1470 }
1471
1472 bool
1473 IOUserServer::checkEntitlements(
1474 OSDictionary * entitlements, OSObject * prop,
1475 IOService * provider, IOService * dext)
1476 {
1477 OSDictionary * matching;
1478
1479 if (!prop) {
1480 return true;
1481 }
1482 if (!entitlements) {
1483 return false;
1484 }
1485
1486 matching = NULL;
1487 if (dext) {
1488 matching = dext->dictionaryWithProperties();
1489 if (!matching) {
1490 return false;
1491 }
1492 }
1493
1494 bool allPresent __block;
1495 prop->iterateObjects(^bool (OSObject * object) {
1496 allPresent = false;
1497 object->iterateObjects(^bool (OSObject * object) {
1498 OSString * string;
1499 OSObject * value;
1500 string = OSDynamicCast(OSString, object);
1501 value = entitlements->getObject(string);
1502 if (matching && value) {
1503 matching->setObject(string, value);
1504 }
1505 allPresent = (NULL != value);
1506 return !allPresent;
1507 });
1508 return allPresent;
1509 });
1510
1511 if (allPresent && matching && provider) {
1512 allPresent = provider->matchPropertyTable(matching);
1513 }
1514
1515 OSSafeReleaseNULL(matching);
1516 OSSafeReleaseNULL(prop);
1517
1518 return allPresent;
1519 }
1520
1521 bool
1522 IOUserServer::checkEntitlements(IOService * provider, IOService * dext)
1523 {
1524 OSObject * prop;
1525 bool ok;
1526
1527 if (!fOwningTask) {
1528 return false;
1529 }
1530
1531 prop = provider->copyProperty(gIOServiceDEXTEntitlementsKey);
1532 ok = checkEntitlements(fEntitlements, prop, provider, dext);
1533 if (!ok) {
1534 DKLOG(DKS ": provider entitlements check failed\n", DKN(dext));
1535 }
1536 if (ok) {
1537 prop = dext->copyProperty(gIOServiceDEXTEntitlementsKey);
1538 ok = checkEntitlements(fEntitlements, prop, NULL, NULL);
1539 if (!ok) {
1540 DKLOG(DKS ": family entitlements check failed\n", DKN(dext));
1541 }
1542 }
1543
1544 return ok;
1545 }
1546
1547 IOReturn
1548 IOUserServer::exit(const char * reason)
1549 {
1550 DKLOG("%s::exit(%s)\n", getName(), reason);
1551 Exit(reason);
1552 return kIOReturnSuccess;
1553 }
1554
1555 OSObjectUserVars *
1556 IOUserServer::varsForObject(OSObject * obj)
1557 {
1558 IOService * service;
1559
1560 if ((service = OSDynamicCast(IOService, obj))) {
1561 return service->reserved->uvars;
1562 }
1563
1564 return NULL;
1565 }
1566
1567 IOPStrings *
1568 IOUserServer::copyInStringArray(const char * string, uint32_t userSize)
1569 {
1570 IOPStrings * array;
1571 vm_size_t alloc;
1572 size_t len;
1573 const char * cstr;
1574 const char * end;
1575
1576 if (userSize <= 1) {
1577 return NULL;
1578 }
1579
1580 if (os_add_overflow(sizeof(IOPStrings), userSize, &alloc)) {
1581 assert(false);
1582 return NULL;
1583 }
1584 if (alloc > 16384) {
1585 assert(false);
1586 return NULL;
1587 }
1588 array = (typeof(array))IOMalloc(alloc);
1589 if (!array) {
1590 return NULL;
1591 }
1592 array->dataSize = userSize;
1593 bcopy(string, (void *) &array->strings[0], userSize);
1594
1595 array->count = 0;
1596 cstr = &array->strings[0];
1597 end = &array->strings[array->dataSize];
1598 while ((len = (unsigned char)cstr[0])) {
1599 cstr++;
1600 if ((cstr + len) >= end) {
1601 break;
1602 }
1603 cstr += len;
1604 array->count++;
1605 }
1606 if (len) {
1607 IOFree(array, alloc);
1608 array = NULL;
1609 }
1610
1611 return array;
1612 }
1613
1614 uint32_t
1615 IOUserServer::stringArrayIndex(IOPStrings * array, const char * look)
1616 {
1617 uint32_t idx;
1618 size_t len, llen;
1619 const char * cstr;
1620 const char * end;
1621
1622 idx = 0;
1623 cstr = &array->strings[0];
1624 end = &array->strings[array->dataSize];
1625 llen = strlen(look);
1626 while ((len = (unsigned char)cstr[0])) {
1627 cstr++;
1628 if ((cstr + len) >= end) {
1629 break;
1630 }
1631 if ((len == llen) && !strncmp(cstr, look, len)) {
1632 return idx;
1633 }
1634 cstr += len;
1635 idx++;
1636 }
1637
1638 return -1U;
1639 }
1640 #define kIODispatchQueueStopped ((IODispatchQueue *) -1L)
1641
1642 IODispatchQueue *
1643 IOUserServer::queueForObject(OSObject * obj, uint64_t msgid)
1644 {
1645 IODispatchQueue * queue;
1646 OSObjectUserVars * uvars;
1647 uint64_t option;
1648
1649 uvars = varsForObject(obj);
1650 if (!uvars) {
1651 return NULL;
1652 }
1653 if (!uvars->queueArray) {
1654 if (uvars->stopped) {
1655 return kIODispatchQueueStopped;
1656 }
1657 return NULL;
1658 }
1659 queue = uvars->queueArray[0];
1660
1661 if (uvars->userMeta
1662 && uvars->userMeta->methods) {
1663 uint32_t idx, baseIdx;
1664 uint32_t lim;
1665 // bsearch
1666 for (baseIdx = 0, lim = uvars->userMeta->methodCount; lim; lim >>= 1) {
1667 idx = baseIdx + (lim >> 1);
1668 if (msgid == uvars->userMeta->methods[idx]) {
1669 option = uvars->userMeta->methods[uvars->userMeta->methodCount + idx];
1670 option &= 0xFF;
1671 if (option < uvars->userMeta->queueNames->count) {
1672 queue = uvars->queueArray[option + 1];
1673 }
1674 break;
1675 } else if (msgid > uvars->userMeta->methods[idx]) {
1676 // move right
1677 baseIdx += (lim >> 1) + 1;
1678 lim--;
1679 }
1680 // else move left
1681 }
1682 }
1683 return queue;
1684 }
1685
1686 IOReturn
1687 IOUserServer::objectInstantiate(OSObject * obj, IORPC rpc, IORPCMessage * message)
1688 {
1689 IOReturn ret;
1690 OSString * str;
1691 OSObject * prop;
1692 IOService * service;
1693
1694 OSAction * action;
1695 OSObject * target;
1696 uint32_t queueCount, queueAlloc;
1697 const char * resultClassName;
1698 uint64_t resultFlags;
1699
1700 size_t replySize;
1701 uint32_t methodCount;
1702 const uint64_t * methods;
1703 IODispatchQueue * queue;
1704 OSUserMetaClass * userMeta;
1705 OSObjectUserVars * uvars;
1706 uint32_t idx;
1707 ipc_port_t sendPort;
1708
1709 OSObject_Instantiate_Rpl_Content * reply;
1710
1711 queueCount = 0;
1712 methodCount = 0;
1713 methods = NULL;
1714 str = NULL;
1715 prop = NULL;
1716 userMeta = NULL;
1717 resultClassName = NULL;
1718 resultFlags = 0;
1719 ret = kIOReturnUnsupportedMode;
1720
1721 service = OSDynamicCast(IOService, obj);
1722 if (!service) {
1723 // xxx other classes hosted
1724 resultFlags |= kOSObjectRPCKernel;
1725 resultFlags |= kOSObjectRPCRemote;
1726 } else {
1727 if (service->isInactive()) {
1728 DKLOG(DKS "::instantiate inactive\n", DKN(service));
1729 return kIOReturnOffline;
1730 }
1731 prop = service->copyProperty(gIOUserClassKey);
1732 str = OSDynamicCast(OSString, prop);
1733 if (!service->reserved->uvars) {
1734 resultFlags |= kOSObjectRPCRemote;
1735 resultFlags |= kOSObjectRPCKernel;
1736 } else if (this != service->reserved->uvars->userServer) {
1737 // remote, use base class
1738 resultFlags |= kOSObjectRPCRemote;
1739 }
1740 if (service->reserved->uvars && service->reserved->uvars->userServer) {
1741 IOLockLock(service->reserved->uvars->userServer->fLock);
1742 userMeta = (typeof(userMeta))service->reserved->uvars->userServer->fClasses->getObject(str);
1743 IOLockUnlock(service->reserved->uvars->userServer->fLock);
1744 }
1745 }
1746 if (!str && !userMeta) {
1747 const OSMetaClass * meta;
1748 meta = obj->getMetaClass();
1749 IOLockLock(fLock);
1750 while (meta && !userMeta) {
1751 str = (OSString *) meta->getClassNameSymbol();
1752 userMeta = (typeof(userMeta))fClasses->getObject(str);
1753 if (!userMeta) {
1754 meta = meta->getSuperClass();
1755 }
1756 }
1757 IOLockUnlock(fLock);
1758 }
1759 if (str) {
1760 if (!userMeta) {
1761 IOLockLock(fLock);
1762 userMeta = (typeof(userMeta))fClasses->getObject(str);
1763 IOLockUnlock(fLock);
1764 }
1765 if (kIODKLogSetup & gIODKDebug) {
1766 DKLOG("userMeta %s %p\n", str->getCStringNoCopy(), userMeta);
1767 }
1768 if (userMeta) {
1769 if (kOSObjectRPCRemote & resultFlags) {
1770 while (userMeta && !(kOSClassCanRemote & userMeta->description->flags)) {
1771 userMeta = userMeta->superMeta;
1772 }
1773 if (userMeta) {
1774 resultClassName = userMeta->description->name;
1775 ret = kIOReturnSuccess;
1776 }
1777 } else {
1778 service->reserved->uvars->userMeta = userMeta;
1779 queueAlloc = 1;
1780 if (userMeta->queueNames) {
1781 queueAlloc += userMeta->queueNames->count;
1782 }
1783 service->reserved->uvars->queueArray =
1784 IONewZero(IODispatchQueue *, queueAlloc);
1785 resultClassName = str->getCStringNoCopy();
1786 ret = kIOReturnSuccess;
1787 }
1788 }
1789 }
1790 OSSafeReleaseNULL(prop);
1791
1792 IORPCMessageMach * machReply = rpc.reply;
1793 replySize = sizeof(OSObject_Instantiate_Rpl);
1794
1795 if ((kIOReturnSuccess == ret) && (kOSObjectRPCRemote & resultFlags)) {
1796 target = obj;
1797 if ((action = OSDynamicCast(OSAction, obj))) {
1798 if (action->ivars->referenceSize) {
1799 resultFlags |= kOSObjectRPCKernel;
1800 } else {
1801 resultFlags &= ~kOSObjectRPCKernel;
1802 target = action->ivars->target;
1803
1804 queueCount = 1;
1805 queue = queueForObject(target, action->ivars->targetmsgid);
1806 idx = 0;
1807 sendPort = NULL;
1808 if (queue && (kIODispatchQueueStopped != queue)) {
1809 sendPort = ipc_port_copy_send(queue->ivars->serverPort);
1810 }
1811 replySize = sizeof(OSObject_Instantiate_Rpl)
1812 + queueCount * sizeof(machReply->objects[0])
1813 + 2 * methodCount * sizeof(reply->methods[0]);
1814 if (replySize > rpc.replySize) {
1815 assert(false);
1816 return kIOReturnIPCError;
1817 }
1818 machReply->objects[idx].type = MACH_MSG_PORT_DESCRIPTOR;
1819 machReply->objects[idx].disposition = MACH_MSG_TYPE_MOVE_SEND;
1820 machReply->objects[idx].name = sendPort;
1821 machReply->objects[idx].pad2 = 0;
1822 machReply->objects[idx].pad_end = 0;
1823 }
1824 } else {
1825 uvars = varsForObject(target);
1826 if (uvars && uvars->userMeta) {
1827 queueCount = 1;
1828 if (uvars->userMeta->queueNames) {
1829 queueCount += uvars->userMeta->queueNames->count;
1830 }
1831 methods = &uvars->userMeta->methods[0];
1832 methodCount = uvars->userMeta->methodCount;
1833 replySize = sizeof(OSObject_Instantiate_Rpl)
1834 + queueCount * sizeof(machReply->objects[0])
1835 + 2 * methodCount * sizeof(reply->methods[0]);
1836 if (replySize > rpc.replySize) {
1837 assert(false);
1838 return kIOReturnIPCError;
1839 }
1840 for (idx = 0; idx < queueCount; idx++) {
1841 queue = uvars->queueArray[idx];
1842 sendPort = NULL;
1843 if (queue) {
1844 sendPort = ipc_port_copy_send(queue->ivars->serverPort);
1845 }
1846 machReply->objects[idx].type = MACH_MSG_PORT_DESCRIPTOR;
1847 machReply->objects[idx].disposition = MACH_MSG_TYPE_MOVE_SEND;
1848 machReply->objects[idx].name = sendPort;
1849 machReply->objects[idx].pad2 = 0;
1850 machReply->objects[idx].pad_end = 0;
1851 }
1852 }
1853 }
1854 }
1855
1856 if (kIODKLogIPC & gIODKDebug) {
1857 DKLOG("instantiate %s\n", obj->getMetaClass()->getClassName());
1858 }
1859
1860 if (kIOReturnSuccess != ret) {
1861 DKLOG("%s: no user class found\n", str ? str->getCStringNoCopy() : obj->getMetaClass()->getClassName());
1862 resultClassName = "unknown";
1863 }
1864
1865 machReply->msgh.msgh_id = kIORPCVersionCurrentReply;
1866 machReply->msgh.msgh_size = replySize;
1867 machReply->msgh_body.msgh_descriptor_count = queueCount;
1868
1869 reply = (typeof(reply))IORPCMessageFromMach(machReply, true);
1870 if (!reply) {
1871 return kIOReturnIPCError;
1872 }
1873 if (methodCount) {
1874 bcopy(methods, &reply->methods[0], methodCount * 2 * sizeof(reply->methods[0]));
1875 }
1876 reply->__hdr.msgid = OSObject_Instantiate_ID;
1877 reply->__hdr.flags = kIORPCMessageOneway;
1878 reply->__hdr.objectRefs = 0;
1879 reply->__pad = 0;
1880 reply->flags = resultFlags;
1881 strlcpy(reply->classname, resultClassName, sizeof(reply->classname));
1882 reply->__result = ret;
1883
1884 ret = kIOReturnSuccess;
1885
1886 return ret;
1887 }
1888
1889 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1890
1891 IOReturn
1892 IOUserServer::kernelDispatch(OSObject * obj, IORPC rpc)
1893 {
1894 IOReturn ret;
1895 IORPCMessage * message;
1896
1897 message = IORPCMessageFromMach(rpc.message, false);
1898 if (!message) {
1899 return kIOReturnIPCError;
1900 }
1901
1902 if (OSObject_Instantiate_ID == message->msgid) {
1903 ret = objectInstantiate(obj, rpc, message);
1904 if (kIOReturnSuccess != ret) {
1905 DKLOG("%s: instantiate failed 0x%x\n", obj->getMetaClass()->getClassName(), ret);
1906 }
1907 } else {
1908 if (kIODKLogIPC & gIODKDebug) {
1909 DKLOG("%s::Dispatch kernel 0x%qx\n", obj->getMetaClass()->getClassName(), message->msgid);
1910 }
1911 ret = obj->Dispatch(rpc);
1912 if (kIODKLogIPC & gIODKDebug) {
1913 DKLOG("%s::Dispatch kernel 0x%qx result 0x%x\n", obj->getMetaClass()->getClassName(), message->msgid, ret);
1914 }
1915 }
1916
1917 return ret;
1918 }
1919
1920
1921 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1922
1923 OSObject *
1924 IOUserServer::target(OSAction * action, IORPCMessage * message)
1925 {
1926 OSObject * object;
1927
1928 if (message->msgid != action->ivars->msgid) {
1929 return action;
1930 }
1931 object = action->ivars->target;
1932 message->msgid = action->ivars->targetmsgid;
1933 message->objects[0] = (OSObjectRef) object;
1934 if (kIORPCMessageRemote & message->flags) {
1935 object->retain();
1936 action->release();
1937 }
1938 if (kIODKLogIPC & gIODKDebug) {
1939 DKLOG("TARGET %s msg 0x%qx from 0x%qx\n", object->getMetaClass()->getClassName(), message->msgid, action->ivars->msgid);
1940 }
1941
1942 return object;
1943 }
1944
1945 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1946
1947 kern_return_t
1948 uext_server(ipc_kmsg_t requestkmsg, ipc_kmsg_t * pReply)
1949 {
1950 kern_return_t ret;
1951 IORPCMessageMach * msgin;
1952 OSObject * object;
1953 IOUserServer * server;
1954
1955 msgin = (typeof(msgin))ipc_kmsg_msg_header(requestkmsg);
1956
1957 object = IOUserServer::copyObjectForSendRight(msgin->msgh.msgh_remote_port, IKOT_UEXT_OBJECT);
1958 server = OSDynamicCast(IOUserServer, object);
1959 if (!server) {
1960 OSSafeReleaseNULL(object);
1961 return KERN_INVALID_NAME;
1962 }
1963 ret = server->server(requestkmsg, pReply);
1964 object->release();
1965
1966 return ret;
1967 }
1968
1969 #define MAX_UEXT_REPLY_SIZE 0x17c0
1970
1971 kern_return_t
1972 IOUserServer::server(ipc_kmsg_t requestkmsg, ipc_kmsg_t * pReply)
1973 {
1974 kern_return_t ret;
1975 mach_msg_size_t replyAlloc;
1976 ipc_kmsg_t replykmsg;
1977 IORPCMessageMach * msgin;
1978 IORPCMessage * message;
1979 IORPCMessageMach * msgout;
1980 IORPCMessage * reply;
1981 uint32_t replySize;
1982 OSObject * object;
1983 OSAction * action;
1984 bool oneway;
1985 uint64_t msgid;
1986
1987 msgin = (typeof(msgin))ipc_kmsg_msg_header(requestkmsg);
1988 replyAlloc = 0;
1989 msgout = NULL;
1990 replykmsg = NULL;
1991
1992 if (msgin->msgh.msgh_size < (sizeof(IORPCMessageMach) + sizeof(IORPCMessage))) {
1993 if (kIODKLogIPC & gIODKDebug) {
1994 DKLOG("UEXT notify %o\n", msgin->msgh.msgh_id);
1995 }
1996 return KERN_NOT_SUPPORTED;
1997 }
1998
1999 if (!(MACH_MSGH_BITS_COMPLEX & msgin->msgh.msgh_bits)) {
2000 msgin->msgh_body.msgh_descriptor_count = 0;
2001 }
2002 message = IORPCMessageFromMach(msgin, false);
2003 if (!message) {
2004 return kIOReturnIPCError;
2005 }
2006 if (message->objectRefs == 0) {
2007 return kIOReturnIPCError;
2008 }
2009 ret = copyInObjects(msgin, message, msgin->msgh.msgh_size, true, false);
2010 if (kIOReturnSuccess != ret) {
2011 if (kIODKLogIPC & gIODKDebug) {
2012 DKLOG("UEXT copyin(0x%x) %x\n", ret, msgin->msgh.msgh_id);
2013 }
2014 return KERN_NOT_SUPPORTED;
2015 }
2016
2017 if (msgin->msgh_body.msgh_descriptor_count < 1) {
2018 return KERN_NOT_SUPPORTED;
2019 }
2020 object = (OSObject *) message->objects[0];
2021 msgid = message->msgid;
2022 message->flags &= ~kIORPCMessageKernel;
2023 message->flags |= kIORPCMessageRemote;
2024
2025 if ((action = OSDynamicCast(OSAction, object))) {
2026 object = target(action, message);
2027 msgid = message->msgid;
2028 }
2029
2030 oneway = (0 != (kIORPCMessageOneway & message->flags));
2031 assert(oneway || (MACH_PORT_NULL != msgin->msgh.msgh_local_port));
2032
2033 // includes trailer size
2034 replyAlloc = oneway ? 0 : MAX_UEXT_REPLY_SIZE;
2035 if (replyAlloc) {
2036 replykmsg = ipc_kmsg_alloc(replyAlloc);
2037 if (replykmsg == NULL) {
2038 // printf("uext_server: dropping request\n");
2039 // ipc_kmsg_trace_send(request, option);
2040 consumeObjects(message, msgin->msgh.msgh_size);
2041 ipc_kmsg_destroy(requestkmsg);
2042 return KERN_MEMORY_FAILURE;
2043 }
2044
2045 msgout = (typeof(msgout))ipc_kmsg_msg_header(replykmsg);
2046 /*
2047 * MIG should really assure no data leakage -
2048 * but until it does, pessimistically zero the
2049 * whole reply buffer.
2050 */
2051 bzero((void *)msgout, replyAlloc);
2052 }
2053
2054 IORPC rpc = { .message = msgin, .reply = msgout, .sendSize = msgin->msgh.msgh_size, .replySize = replyAlloc };
2055
2056 if (object) {
2057 thread_iokit_tls_set(0, this);
2058 ret = kernelDispatch(object, rpc);
2059 thread_iokit_tls_set(0, NULL);
2060 } else {
2061 ret = kIOReturnBadArgument;
2062 }
2063
2064 // release objects
2065 consumeObjects(message, msgin->msgh.msgh_size);
2066
2067 // release ports
2068 copyInObjects(msgin, message, msgin->msgh.msgh_size, false, true);
2069
2070 if (!oneway) {
2071 if (kIOReturnSuccess == ret) {
2072 replySize = msgout->msgh.msgh_size;
2073 reply = IORPCMessageFromMach(msgout, true);
2074 if (!reply) {
2075 ret = kIOReturnIPCError;
2076 } else {
2077 ret = copyOutObjects(msgout, reply, replySize, (kIORPCVersionCurrentReply == msgout->msgh.msgh_id) /* =>!InvokeReply */);
2078 }
2079 }
2080 if (kIOReturnSuccess != ret) {
2081 IORPCMessageErrorReturnContent * errorMsg;
2082
2083 msgout->msgh_body.msgh_descriptor_count = 0;
2084 msgout->msgh.msgh_id = kIORPCVersionCurrentReply;
2085 errorMsg = (typeof(errorMsg))IORPCMessageFromMach(msgout, true);
2086 errorMsg->hdr.msgid = message->msgid;
2087 errorMsg->hdr.flags = kIORPCMessageOneway | kIORPCMessageError;
2088 errorMsg->hdr.objectRefs = 0;
2089 errorMsg->result = ret;
2090 errorMsg->pad = 0;
2091 replySize = sizeof(IORPCMessageErrorReturn);
2092 }
2093
2094 msgout->msgh.msgh_bits = MACH_MSGH_BITS_COMPLEX |
2095 MACH_MSGH_BITS_SET(MACH_MSGH_BITS_LOCAL(msgin->msgh.msgh_bits) /*remote*/, 0 /*local*/, 0, 0);
2096
2097 msgout->msgh.msgh_remote_port = msgin->msgh.msgh_local_port;
2098 msgout->msgh.msgh_local_port = MACH_PORT_NULL;
2099 msgout->msgh.msgh_voucher_port = (mach_port_name_t) 0;
2100 msgout->msgh.msgh_reserved = 0;
2101 msgout->msgh.msgh_size = replySize;
2102 }
2103
2104 *pReply = replykmsg;
2105
2106 return oneway ? MIG_NO_REPLY : KERN_SUCCESS;
2107 }
2108
2109 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2110
2111 #define MAX_OBJECT_COUNT(mach, size, message) \
2112 ((((size) + ((uintptr_t) (mach))) - ((uintptr_t) (&message->objects[0]))) / sizeof(OSObjectRef))
2113
2114 kern_return_t
2115 IOUserServerUEXTTrap(OSObject * object, void * p1, void * p2, void * p3, void * p4, void * p5, void * p6)
2116 {
2117 const user_addr_t msg = (uintptr_t) p1;
2118 size_t inSize = (uintptr_t) p2;
2119 user_addr_t out = (uintptr_t) p3;
2120 size_t outSize = (uintptr_t) p4;
2121 mach_port_name_t objectName1 = (uintptr_t) p5;
2122 size_t totalSize;
2123 OSObject * objectArg1;
2124
2125 IORPCMessageMach * mach;
2126 mach_msg_port_descriptor_t * descs;
2127
2128 #pragma pack(4)
2129 struct {
2130 uint32_t pad;
2131 IORPCMessageMach mach;
2132 mach_msg_port_descriptor_t objects[2];
2133 IOTrapMessageBuffer buffer;
2134 } buffer;
2135 #pragma pack()
2136
2137 IOReturn ret;
2138 OSAction * action;
2139 int copyerr;
2140 IORPCMessage * message;
2141 IORPCMessage * reply;
2142 IORPC rpc;
2143 uint64_t refs;
2144 uint32_t maxObjectCount;
2145 size_t copySize;
2146 uint64_t * replyHdr;
2147 uintptr_t p;
2148
2149 bzero(&buffer, sizeof(buffer));
2150
2151 p = (typeof(p)) & buffer.buffer[0];
2152 if (os_add_overflow(inSize, outSize, &totalSize)) {
2153 return kIOReturnMessageTooLarge;
2154 }
2155 if (totalSize > sizeof(buffer.buffer)) {
2156 return kIOReturnMessageTooLarge;
2157 }
2158 if (inSize < sizeof(IORPCMessage)) {
2159 return kIOReturnIPCError;
2160 }
2161 copyerr = copyin(msg, &buffer.buffer[0], inSize);
2162 if (copyerr) {
2163 return kIOReturnVMError;
2164 }
2165
2166 message = (typeof(message))p;
2167 refs = message->objectRefs;
2168 if ((refs > 2) || !refs) {
2169 return kIOReturnUnsupported;
2170 }
2171 if (!(kIORPCMessageSimpleReply & message->flags)) {
2172 return kIOReturnUnsupported;
2173 }
2174
2175 descs = (typeof(descs))(p - refs * sizeof(*descs));
2176 mach = (typeof(mach))(p - refs * sizeof(*descs) - sizeof(*mach));
2177
2178 mach->msgh.msgh_id = kIORPCVersionCurrent;
2179 mach->msgh.msgh_size = sizeof(IORPCMessageMach) + refs * sizeof(*descs) + inSize;
2180 mach->msgh_body.msgh_descriptor_count = refs;
2181
2182 rpc.message = mach;
2183 rpc.sendSize = mach->msgh.msgh_size;
2184 rpc.reply = (IORPCMessageMach *) (p + inSize);
2185 rpc.replySize = sizeof(buffer.buffer) - inSize;
2186
2187 message->objects[0] = 0;
2188 if ((action = OSDynamicCast(OSAction, object))) {
2189 maxObjectCount = MAX_OBJECT_COUNT(rpc.message, rpc.sendSize, message);
2190 if (refs > maxObjectCount) {
2191 return kIOReturnBadArgument;
2192 }
2193 object = IOUserServer::target(action, message);
2194 message->objects[1] = (OSObjectRef) action;
2195 if (kIODKLogIPC & gIODKDebug) {
2196 DKLOG("%s::Dispatch(trap) kernel 0x%qx\n", object->getMetaClass()->getClassName(), message->msgid);
2197 }
2198 ret = object->Dispatch(rpc);
2199 } else {
2200 objectArg1 = NULL;
2201 if (refs > 1) {
2202 objectArg1 = iokit_lookup_uext_ref_current_task(objectName1);
2203 if (!objectArg1) {
2204 return kIOReturnIPCError;
2205 }
2206 message->objects[1] = (OSObjectRef) objectArg1;
2207 }
2208 if (kIODKLogIPC & gIODKDebug) {
2209 DKLOG("%s::Dispatch(trap) kernel 0x%qx\n", object->getMetaClass()->getClassName(), message->msgid);
2210 }
2211 ret = object->Dispatch(rpc);
2212 if (kIODKLogIPC & gIODKDebug) {
2213 DKLOG("%s::Dispatch(trap) kernel 0x%qx 0x%x\n", object->getMetaClass()->getClassName(), message->msgid, ret);
2214 }
2215 OSSafeReleaseNULL(objectArg1);
2216
2217 if (kIOReturnSuccess == ret) {
2218 if (rpc.reply->msgh_body.msgh_descriptor_count) {
2219 return kIOReturnIPCError;
2220 }
2221 reply = IORPCMessageFromMach(rpc.reply, rpc.reply->msgh.msgh_size);
2222 if (!reply) {
2223 return kIOReturnIPCError;
2224 }
2225 copySize = rpc.reply->msgh.msgh_size - (((uintptr_t) reply) - ((uintptr_t) rpc.reply)) + sizeof(uint64_t);
2226 if (copySize > outSize) {
2227 return kIOReturnIPCError;
2228 }
2229 replyHdr = (uint64_t *) reply;
2230 replyHdr--;
2231 replyHdr[0] = copySize;
2232 copyerr = copyout(replyHdr, out, copySize);
2233 if (copyerr) {
2234 return kIOReturnVMError;
2235 }
2236 }
2237 }
2238
2239 return ret;
2240 }
2241
2242 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2243
2244 IOReturn
2245 IOUserServer::rpc(IORPC rpc)
2246 {
2247 if (isInactive() && !fRootQueue) {
2248 return kIOReturnOffline;
2249 }
2250
2251 IOReturn ret;
2252 IORPCMessage * message;
2253 IORPCMessageMach * mach;
2254 mach_msg_id_t machid;
2255 uint32_t sendSize, replySize;
2256 bool oneway;
2257 uint64_t msgid;
2258 IODispatchQueue * queue;
2259 IOService * service;
2260 ipc_port_t port;
2261 ipc_port_t sendPort;
2262
2263 queue = NULL;
2264 port = NULL;
2265 sendPort = NULL;
2266
2267 mach = rpc.message;
2268 sendSize = rpc.sendSize;
2269 replySize = rpc.replySize;
2270
2271 assert(sendSize >= (sizeof(IORPCMessageMach) + sizeof(IORPCMessage)));
2272
2273 message = IORPCMessageFromMach(mach, false);
2274 if (!message) {
2275 ret = kIOReturnIPCError;
2276 }
2277 msgid = message->msgid;
2278 machid = (msgid >> 32);
2279
2280 if (mach->msgh_body.msgh_descriptor_count < 1) {
2281 return kIOReturnNoMedia;
2282 }
2283
2284 IOLockLock(gIOUserServerLock);
2285 if ((service = OSDynamicCast(IOService, (OSObject *) message->objects[0]))) {
2286 queue = queueForObject(service, msgid);
2287 }
2288 if (!queue) {
2289 queue = fRootQueue;
2290 }
2291 if (queue && (kIODispatchQueueStopped != queue)) {
2292 port = queue->ivars->serverPort;
2293 }
2294 if (port) {
2295 sendPort = ipc_port_copy_send(port);
2296 }
2297 IOLockUnlock(gIOUserServerLock);
2298 if (!sendPort) {
2299 return kIOReturnNotReady;
2300 }
2301
2302 oneway = (0 != (kIORPCMessageOneway & message->flags));
2303
2304 ret = copyOutObjects(mach, message, sendSize, false);
2305
2306 mach->msgh.msgh_bits = MACH_MSGH_BITS_COMPLEX |
2307 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, (oneway ? 0 : MACH_MSG_TYPE_MAKE_SEND_ONCE));
2308 mach->msgh.msgh_remote_port = sendPort;
2309 mach->msgh.msgh_local_port = (oneway ? MACH_PORT_NULL : mig_get_reply_port());
2310 mach->msgh.msgh_id = kIORPCVersionCurrent;
2311 mach->msgh.msgh_reserved = 0;
2312
2313 boolean_t message_moved;
2314
2315 if (oneway) {
2316 ret = kernel_mach_msg_send(&mach->msgh, sendSize,
2317 MACH_SEND_MSG | MACH_SEND_ALWAYS | MACH_SEND_NOIMPORTANCE,
2318 0, &message_moved);
2319 } else {
2320 assert(replySize >= (sizeof(IORPCMessageMach) + sizeof(IORPCMessage)));
2321 ret = kernel_mach_msg_rpc(&mach->msgh, sendSize, replySize, FALSE, &message_moved);
2322 }
2323
2324 ipc_port_release_send(sendPort);
2325
2326 if (MACH_MSG_SUCCESS != ret) {
2327 if (kIODKLogIPC & gIODKDebug) {
2328 DKLOG("mach_msg() failed 0x%x\n", ret);
2329 }
2330 if (!message_moved) {
2331 // release ports
2332 copyInObjects(mach, message, sendSize, false, true);
2333 }
2334 }
2335
2336 if ((KERN_SUCCESS == ret) && !oneway) {
2337 if (kIORPCVersionCurrentReply != mach->msgh.msgh_id) {
2338 ret = (MACH_NOTIFY_SEND_ONCE == mach->msgh.msgh_id) ? MIG_SERVER_DIED : MIG_REPLY_MISMATCH;
2339 } else if ((replySize = mach->msgh.msgh_size) < (sizeof(IORPCMessageMach) + sizeof(IORPCMessage))) {
2340 // printf("BAD REPLY SIZE\n");
2341 ret = MIG_BAD_ARGUMENTS;
2342 } else {
2343 if (!(MACH_MSGH_BITS_COMPLEX & mach->msgh.msgh_bits)) {
2344 mach->msgh_body.msgh_descriptor_count = 0;
2345 }
2346 message = IORPCMessageFromMach(mach, true);
2347 if (!message) {
2348 ret = kIOReturnIPCError;
2349 } else if (message->msgid != msgid) {
2350 // printf("BAD REPLY ID\n");
2351 ret = MIG_BAD_ARGUMENTS;
2352 } else {
2353 bool isError = (0 != (kIORPCMessageError & message->flags));
2354 ret = copyInObjects(mach, message, replySize, !isError, true);
2355 if (kIOReturnSuccess != ret) {
2356 if (kIODKLogIPC & gIODKDebug) {
2357 DKLOG("rpc copyin(0x%x) %x\n", ret, mach->msgh.msgh_id);
2358 }
2359 return KERN_NOT_SUPPORTED;
2360 }
2361 if (isError) {
2362 IORPCMessageErrorReturnContent * errorMsg = (typeof(errorMsg))message;
2363 ret = errorMsg->result;
2364 }
2365 }
2366 }
2367 }
2368
2369 return ret;
2370 }
2371
2372 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2373
2374 IORPCMessage *
2375 IORPCMessageFromMach(IORPCMessageMach * msg, bool reply)
2376 {
2377 mach_msg_size_t idx, count;
2378 mach_msg_port_descriptor_t * desc;
2379 mach_msg_port_descriptor_t * maxDesc;
2380 size_t size, msgsize;
2381 bool upgrade;
2382
2383 msgsize = msg->msgh.msgh_size;
2384 count = msg->msgh_body.msgh_descriptor_count;
2385 desc = &msg->objects[0];
2386 maxDesc = (typeof(maxDesc))(((uintptr_t) msg) + msgsize);
2387 upgrade = (msg->msgh.msgh_id != (reply ? kIORPCVersionCurrentReply : kIORPCVersionCurrent));
2388
2389 if (upgrade) {
2390 OSReportWithBacktrace("obsolete message");
2391 return NULL;
2392 }
2393
2394 for (idx = 0; idx < count; idx++) {
2395 if (desc >= maxDesc) {
2396 return NULL;
2397 }
2398 switch (desc->type) {
2399 case MACH_MSG_PORT_DESCRIPTOR:
2400 size = sizeof(mach_msg_port_descriptor_t);
2401 break;
2402 case MACH_MSG_OOL_DESCRIPTOR:
2403 size = sizeof(mach_msg_ool_descriptor_t);
2404 break;
2405 default:
2406 return NULL;
2407 }
2408 desc = (typeof(desc))(((uintptr_t) desc) + size);
2409 }
2410 return (IORPCMessage *)(uintptr_t) desc;
2411 }
2412
2413 ipc_port_t
2414 IOUserServer::copySendRightForObject(OSObject * object, ipc_kobject_type_t type)
2415 {
2416 ipc_port_t port;
2417 ipc_port_t sendPort = NULL;
2418
2419 port = iokit_port_for_object(object, type);
2420 if (port) {
2421 sendPort = ipc_port_make_send(port);
2422 iokit_release_port(port);
2423 }
2424
2425 return sendPort;
2426 }
2427
2428 OSObject *
2429 IOUserServer::copyObjectForSendRight(ipc_port_t port, ipc_kobject_type_t type)
2430 {
2431 OSObject * object;
2432 object = iokit_lookup_io_object(port, type);
2433 return object;
2434 }
2435
2436 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2437
2438 // Create a vm_map_copy_t or kalloc'ed data for memory
2439 // to be copied out. ipc will free after the copyout.
2440
2441 static kern_return_t
2442 copyoutkdata(const void * data, vm_size_t len, void ** buf)
2443 {
2444 kern_return_t err;
2445 vm_map_copy_t copy;
2446
2447 err = vm_map_copyin( kernel_map, CAST_USER_ADDR_T(data), len,
2448 false /* src_destroy */, &copy);
2449
2450 assert( err == KERN_SUCCESS );
2451 if (err == KERN_SUCCESS) {
2452 *buf = (char *) copy;
2453 }
2454
2455 return err;
2456 }
2457
2458 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2459
2460 IOReturn
2461 IOUserServer::copyOutObjects(IORPCMessageMach * mach, IORPCMessage * message,
2462 size_t size, bool consume)
2463 {
2464 uint64_t refs;
2465 uint32_t idx, maxObjectCount;
2466 ipc_port_t port;
2467 OSObject * object;
2468 size_t descsize;
2469 mach_msg_port_descriptor_t * desc;
2470 mach_msg_ool_descriptor_t * ool;
2471 vm_map_copy_t copy;
2472 void * address;
2473 mach_msg_size_t length;
2474 kern_return_t kr;
2475 OSSerialize * s;
2476
2477 refs = message->objectRefs;
2478 maxObjectCount = MAX_OBJECT_COUNT(mach, size, message);
2479 // assert(refs <= mach->msgh_body.msgh_descriptor_count);
2480 // assert(refs <= maxObjectCount);
2481 if (refs > mach->msgh_body.msgh_descriptor_count) {
2482 return kIOReturnBadArgument;
2483 }
2484 if (refs > maxObjectCount) {
2485 return kIOReturnBadArgument;
2486 }
2487
2488 desc = &mach->objects[0];
2489 for (idx = 0; idx < refs; idx++) {
2490 object = (OSObject *) message->objects[idx];
2491
2492 switch (desc->type) {
2493 case MACH_MSG_PORT_DESCRIPTOR:
2494 descsize = sizeof(mach_msg_port_descriptor_t);
2495 port = NULL;
2496 if (object) {
2497 port = copySendRightForObject(object, IKOT_UEXT_OBJECT);
2498 if (!port) {
2499 break;
2500 }
2501 if (consume) {
2502 object->release();
2503 }
2504 message->objects[idx] = 0;
2505 }
2506 // desc->type = MACH_MSG_PORT_DESCRIPTOR;
2507 desc->disposition = MACH_MSG_TYPE_MOVE_SEND;
2508 desc->name = port;
2509 desc->pad2 = 0;
2510 desc->pad_end = 0;
2511 break;
2512
2513 case MACH_MSG_OOL_DESCRIPTOR:
2514 descsize = sizeof(mach_msg_ool_descriptor_t);
2515
2516 length = 0;
2517 address = NULL;
2518 if (object) {
2519 s = OSSerialize::binaryWithCapacity(4096);
2520 assert(s);
2521 if (!s) {
2522 break;
2523 }
2524 s->setIndexed(true);
2525 if (!object->serialize(s)) {
2526 assert(false);
2527 descsize = -1UL;
2528 s->release();
2529 break;
2530 }
2531 length = s->getLength();
2532 kr = copyoutkdata(s->text(), length, &address);
2533 s->release();
2534 if (KERN_SUCCESS != kr) {
2535 descsize = -1UL;
2536 address = NULL;
2537 length = 0;
2538 }
2539 if (consume) {
2540 object->release();
2541 }
2542 message->objects[idx] = 0;
2543 }
2544 ool = (typeof(ool))desc;
2545 // ool->type = MACH_MSG_OOL_DESCRIPTOR;
2546 ool->deallocate = false;
2547 ool->copy = MACH_MSG_PHYSICAL_COPY;
2548 ool->size = length;
2549 ool->address = address;
2550 break;
2551
2552 default:
2553 descsize = -1UL;
2554 break;
2555 }
2556 if (-1UL == descsize) {
2557 break;
2558 }
2559 desc = (typeof(desc))(((uintptr_t) desc) + descsize);
2560 }
2561
2562 if (idx >= refs) {
2563 return kIOReturnSuccess;
2564 }
2565
2566 desc = &mach->objects[0];
2567 while (idx--) {
2568 switch (desc->type) {
2569 case MACH_MSG_PORT_DESCRIPTOR:
2570 descsize = sizeof(mach_msg_port_descriptor_t);
2571 port = desc->name;
2572 if (port) {
2573 ipc_port_release_send(port);
2574 }
2575 break;
2576
2577 case MACH_MSG_OOL_DESCRIPTOR:
2578 descsize = sizeof(mach_msg_ool_descriptor_t);
2579 ool = (typeof(ool))desc;
2580 copy = (vm_map_copy_t) ool->address;
2581 if (copy) {
2582 vm_map_copy_discard(copy);
2583 }
2584 break;
2585
2586 default:
2587 descsize = -1UL;
2588 break;
2589 }
2590 if (-1UL == descsize) {
2591 break;
2592 }
2593 desc = (typeof(desc))(((uintptr_t) desc) + descsize);
2594 }
2595
2596 return kIOReturnBadArgument;
2597 }
2598
2599 IOReturn
2600 IOUserServer::copyInObjects(IORPCMessageMach * mach, IORPCMessage * message,
2601 size_t size, bool copyObjects, bool consumePorts)
2602 {
2603 uint64_t refs;
2604 uint32_t idx, maxObjectCount;
2605 ipc_port_t port;
2606 OSObject * object;
2607 size_t descsize;
2608 mach_msg_port_descriptor_t * desc;
2609 mach_msg_ool_descriptor_t * ool;
2610 vm_map_address_t copyoutdata;
2611 kern_return_t kr;
2612
2613 refs = message->objectRefs;
2614 maxObjectCount = MAX_OBJECT_COUNT(mach, size, message);
2615 // assert(refs <= mach->msgh_body.msgh_descriptor_count);
2616 // assert(refs <= maxObjectCount);
2617 if (refs > mach->msgh_body.msgh_descriptor_count) {
2618 return kIOReturnBadArgument;
2619 }
2620 if (refs > maxObjectCount) {
2621 return kIOReturnBadArgument;
2622 }
2623
2624 desc = &mach->objects[0];
2625 for (idx = 0; idx < refs; idx++) {
2626 switch (desc->type) {
2627 case MACH_MSG_PORT_DESCRIPTOR:
2628 descsize = sizeof(mach_msg_port_descriptor_t);
2629
2630 object = NULL;
2631 port = desc->name;
2632 if (port) {
2633 if (copyObjects) {
2634 object = copyObjectForSendRight(port, IKOT_UEXT_OBJECT);
2635 if (!object) {
2636 descsize = -1UL;
2637 break;
2638 }
2639 }
2640 if (consumePorts) {
2641 ipc_port_release_send(port);
2642 }
2643 }
2644 break;
2645
2646 case MACH_MSG_OOL_DESCRIPTOR:
2647 descsize = sizeof(mach_msg_ool_descriptor_t);
2648 ool = (typeof(ool))desc;
2649
2650 object = NULL;
2651 if (copyObjects && ool->size && ool->address) {
2652 kr = vm_map_copyout(kernel_map, &copyoutdata, (vm_map_copy_t) ool->address);
2653 if (KERN_SUCCESS == kr) {
2654 object = OSUnserializeXML((const char *) copyoutdata, ool->size);
2655 // vm_map_copyout() has consumed the vm_map_copy_t in the message
2656 ool->size = 0;
2657 ool->address = NULL;
2658 kr = vm_deallocate(kernel_map, copyoutdata, ool->size);
2659 assert(KERN_SUCCESS == kr);
2660 }
2661 if (!object) {
2662 descsize = -1UL;
2663 break;
2664 }
2665 }
2666 break;
2667
2668 default:
2669 descsize = -1UL;
2670 break;
2671 }
2672 if (-1UL == descsize) {
2673 break;
2674 }
2675 if (copyObjects) {
2676 message->objects[idx] = (OSObjectRef) object;
2677 }
2678 desc = (typeof(desc))(((uintptr_t) desc) + descsize);
2679 }
2680
2681 if (idx >= refs) {
2682 return kIOReturnSuccess;
2683 }
2684
2685 while (idx--) {
2686 object = (OSObject *) message->objects[idx];
2687 object->release();
2688 message->objects[idx] = 0;
2689 }
2690
2691 return kIOReturnBadArgument;
2692 }
2693
2694 IOReturn
2695 IOUserServer::consumeObjects(IORPCMessage * message, size_t messageSize)
2696 {
2697 uint64_t refs, idx;
2698 OSObject * object;
2699
2700 refs = message->objectRefs;
2701 for (idx = 0; idx < refs; idx++) {
2702 object = (OSObject *) message->objects[idx];
2703 if (object) {
2704 object->release();
2705 message->objects[idx] = 0;
2706 }
2707 }
2708
2709 return kIOReturnSuccess;
2710 }
2711
2712 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2713
2714 bool
2715 IOUserServer::finalize(IOOptionBits options)
2716 {
2717 OSArray * services;
2718
2719 if (kIODKLogSetup & gIODKDebug) {
2720 DKLOG("%s::finalize(%p)\n", getName(), this);
2721 }
2722
2723 IOLockLock(gIOUserServerLock);
2724 OSSafeReleaseNULL(fRootQueue);
2725 IOLockUnlock(gIOUserServerLock);
2726
2727 services = NULL;
2728 IOLockLock(fLock);
2729 if (fServices) {
2730 services = OSArray::withArray(fServices);
2731 }
2732 IOLockUnlock(fLock);
2733
2734 if (services) {
2735 services->iterateObjects(^bool (OSObject * obj) {
2736 IOService * service;
2737 IOService * provider;
2738 bool started = false;
2739
2740 service = (IOService *) obj;
2741 if (kIODKLogSetup & gIODKDebug) {
2742 DKLOG("%s::terminate(" DKS ")\n", getName(), DKN(service));
2743 }
2744 if (service->reserved->uvars) {
2745 started = service->reserved->uvars->started;
2746 service->reserved->uvars->serverDied = true;
2747 if (started) {
2748 provider = service->getProvider();
2749 serviceDidStop(service, provider);
2750 service->terminate(kIOServiceTerminateNeedWillTerminate | kIOServiceTerminateWithRematch);
2751 }
2752 }
2753 if (!started) {
2754 DKLOG("%s::terminate(" DKS ") server exit before start()\n", getName(), DKN(service));
2755 serviceStop(service, NULL);
2756 }
2757 return false;
2758 });
2759 services->release();
2760 }
2761
2762 return IOUserClient::finalize(options);
2763 }
2764
2765 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2766
2767 #undef super
2768 #define super IOUserClient
2769
2770 OSDefineMetaClassAndStructors(IOUserServer, IOUserClient)
2771
2772 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2773
2774 IOUserClient * IOUserServer::withTask(task_t owningTask)
2775 {
2776 IOUserServer * inst;
2777
2778 inst = new IOUserServer;
2779 if (inst && !inst->init()) {
2780 inst->release();
2781 inst = NULL;
2782 return inst;
2783 }
2784 inst->PMinit();
2785
2786 inst->fOwningTask = current_task();
2787 inst->fEntitlements = IOUserClient::copyClientEntitlements(inst->fOwningTask);
2788
2789 if (!(kIODKDisableEntitlementChecking & gIODKDebug)) {
2790 if (!inst->fEntitlements || !inst->fEntitlements->getObject(gIODriverKitEntitlementKey)) {
2791 proc_t p;
2792 pid_t pid;
2793
2794 p = (proc_t)get_bsdtask_info(inst->fOwningTask);
2795 if (p) {
2796 pid = proc_pid(p);
2797 IOLog(kIODriverKitEntitlementKey " entitlement check failed for %s[%d]\n", proc_best_name(p), pid);
2798 }
2799 inst->release();
2800 inst = NULL;
2801 return inst;
2802 }
2803 }
2804
2805 /* Mark the current task's space as eligible for uext object ports */
2806 iokit_label_dext_task(inst->fOwningTask);
2807
2808 inst->fLock = IOLockAlloc();
2809 inst->fServices = OSArray::withCapacity(4);
2810 inst->fClasses = OSDictionary::withCapacity(16);
2811 inst->fClasses->setOptions(OSCollection::kSort, OSCollection::kSort);
2812
2813 return inst;
2814 }
2815
2816 IOReturn
2817 IOUserServer::clientClose(void)
2818 {
2819 terminate();
2820 return kIOReturnSuccess;
2821 }
2822
2823 IOReturn
2824 IOUserServer::setProperties(OSObject * properties)
2825 {
2826 IOReturn kr = kIOReturnUnsupported;
2827 return kr;
2828 }
2829
2830 void
2831 IOUserServer::stop(IOService * provider)
2832 {
2833 fOwningTask = TASK_NULL;
2834
2835 PMstop();
2836
2837 IOServicePH::serverRemove(this);
2838
2839 OSSafeReleaseNULL(fRootQueue);
2840
2841 if (fInterruptLock) {
2842 IOSimpleLockFree(fInterruptLock);
2843 }
2844 }
2845
2846 void
2847 IOUserServer::free()
2848 {
2849 OSSafeReleaseNULL(fEntitlements);
2850 OSSafeReleaseNULL(fClasses);
2851 if (fLock) {
2852 IOLockFree(fLock);
2853 }
2854 OSSafeReleaseNULL(fServices);
2855 IOUserClient::free();
2856 }
2857
2858 IOReturn
2859 IOUserServer::registerClass(OSClassDescription * desc, uint32_t size, OSUserMetaClass ** pCls)
2860 {
2861 OSUserMetaClass * cls;
2862 const OSSymbol * sym;
2863 uint64_t * methodOptions;
2864 const char * queueNames;
2865 uint32_t methodOptionsEnd, queueNamesEnd;
2866 IOReturn ret = kIOReturnSuccess;
2867
2868 if (size < sizeof(OSClassDescription)) {
2869 assert(false);
2870 return kIOReturnBadArgument;
2871 }
2872
2873 if (kIODKLogSetup & gIODKDebug) {
2874 DKLOG("%s::registerClass %s, %d, %d\n", getName(), desc->name, desc->queueNamesSize, desc->methodNamesSize);
2875 }
2876
2877 if (desc->descriptionSize != size) {
2878 assert(false);
2879 return kIOReturnBadArgument;
2880 }
2881 if (os_add_overflow(desc->queueNamesOffset, desc->queueNamesSize, &queueNamesEnd)) {
2882 assert(false);
2883 return kIOReturnBadArgument;
2884 }
2885 if (queueNamesEnd > size) {
2886 assert(false);
2887 return kIOReturnBadArgument;
2888 }
2889 if (os_add_overflow(desc->methodOptionsOffset, desc->methodOptionsSize, &methodOptionsEnd)) {
2890 assert(false);
2891 return kIOReturnBadArgument;
2892 }
2893 if (methodOptionsEnd > size) {
2894 assert(false);
2895 return kIOReturnBadArgument;
2896 }
2897 // overlaps?
2898 if ((desc->queueNamesOffset >= desc->methodOptionsOffset) && (desc->queueNamesOffset < methodOptionsEnd)) {
2899 assert(false);
2900 return kIOReturnBadArgument;
2901 }
2902 if ((queueNamesEnd >= desc->methodOptionsOffset) && (queueNamesEnd < methodOptionsEnd)) {
2903 assert(false);
2904 return kIOReturnBadArgument;
2905 }
2906
2907 if (desc->methodOptionsSize & ((2 * sizeof(uint64_t)) - 1)) {
2908 assert(false);
2909 return kIOReturnBadArgument;
2910 }
2911 if (sizeof(desc->name) == strnlen(desc->name, sizeof(desc->name))) {
2912 assert(false);
2913 return kIOReturnBadArgument;
2914 }
2915 if (sizeof(desc->superName) == strnlen(desc->superName, sizeof(desc->superName))) {
2916 assert(false);
2917 return kIOReturnBadArgument;
2918 }
2919
2920 cls = OSTypeAlloc(OSUserMetaClass);
2921 assert(cls);
2922 if (!cls) {
2923 return kIOReturnNoMemory;
2924 }
2925
2926 cls->description = (typeof(cls->description))IOMalloc(size);
2927 assert(cls->description);
2928 if (!cls->description) {
2929 assert(false);
2930 cls->release();
2931 return kIOReturnNoMemory;
2932 }
2933 bcopy(desc, cls->description, size);
2934
2935 cls->methodCount = desc->methodOptionsSize / (2 * sizeof(uint64_t));
2936 cls->methods = IONew(uint64_t, 2 * cls->methodCount);
2937 if (!cls->methods) {
2938 assert(false);
2939 cls->release();
2940 return kIOReturnNoMemory;
2941 }
2942
2943 methodOptions = (typeof(methodOptions))(((uintptr_t) desc) + desc->methodOptionsOffset);
2944 bcopy(methodOptions, cls->methods, 2 * cls->methodCount * sizeof(uint64_t));
2945
2946 queueNames = (typeof(queueNames))(((uintptr_t) desc) + desc->queueNamesOffset);
2947 cls->queueNames = copyInStringArray(queueNames, desc->queueNamesSize);
2948
2949 sym = OSSymbol::withCString(desc->name);
2950 assert(sym);
2951 if (!sym) {
2952 assert(false);
2953 cls->release();
2954 return kIOReturnNoMemory;
2955 }
2956
2957 cls->name = sym;
2958 cls->meta = OSMetaClass::copyMetaClassWithName(sym);
2959 IOLockLock(fLock);
2960 cls->superMeta = OSDynamicCast(OSUserMetaClass, fClasses->getObject(desc->superName));
2961 if (fClasses->getObject(sym) != NULL) {
2962 /* class with this name exists */
2963 ret = kIOReturnBadArgument;
2964 } else {
2965 if (fClasses->setObject(sym, cls)) {
2966 *pCls = cls;
2967 } else {
2968 /* could not add class to fClasses */
2969 ret = kIOReturnNoMemory;
2970 }
2971 }
2972 IOLockUnlock(fLock);
2973 cls->release();
2974 return ret;
2975 }
2976
2977 IOReturn
2978 IOUserServer::setRootQueue(IODispatchQueue * queue)
2979 {
2980 assert(!fRootQueue);
2981 if (fRootQueue) {
2982 return kIOReturnStillOpen;
2983 }
2984 queue->retain();
2985 fRootQueue = queue;
2986
2987 return kIOReturnSuccess;
2988 }
2989
2990 IOReturn
2991 IOUserServer::externalMethod(uint32_t selector, IOExternalMethodArguments * args,
2992 IOExternalMethodDispatch * dispatch, OSObject * target, void * reference)
2993 {
2994 IOReturn ret = kIOReturnBadArgument;
2995 mach_port_name_t portname;
2996
2997 switch (selector) {
2998 case kIOUserServerMethodRegisterClass:
2999 {
3000 OSUserMetaClass * cls;
3001 if (!args->structureInputSize) {
3002 return kIOReturnBadArgument;
3003 }
3004 if (args->scalarOutputCount != 2) {
3005 return kIOReturnBadArgument;
3006 }
3007 ret = registerClass((OSClassDescription *) args->structureInput, args->structureInputSize, &cls);
3008 if (kIOReturnSuccess == ret) {
3009 portname = iokit_make_send_right(fOwningTask, cls, IKOT_UEXT_OBJECT);
3010 assert(portname);
3011 args->scalarOutput[0] = portname;
3012 args->scalarOutput[1] = kOSObjectRPCRemote;
3013 }
3014 break;
3015 }
3016 case kIOUserServerMethodStart:
3017 {
3018 if (args->scalarOutputCount != 1) {
3019 return kIOReturnBadArgument;
3020 }
3021 portname = iokit_make_send_right(fOwningTask, this, IKOT_UEXT_OBJECT);
3022 assert(portname);
3023 args->scalarOutput[0] = portname;
3024 ret = kIOReturnSuccess;
3025 break;
3026 }
3027 default:
3028 break;
3029 }
3030
3031 return ret;
3032 }
3033
3034 IOExternalTrap *
3035 IOUserServer::getTargetAndTrapForIndex( IOService **targetP, UInt32 index )
3036 {
3037 static const IOExternalTrap trapTemplate[] = {
3038 { NULL, (IOTrap) & IOUserServer::waitInterruptTrap},
3039 };
3040 if (index >= (sizeof(trapTemplate) / sizeof(IOExternalTrap))) {
3041 return NULL;
3042 }
3043 *targetP = this;
3044 return (IOExternalTrap *)&trapTemplate[index];
3045 }
3046
3047 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3048
3049 IOReturn
3050 IOUserServer::serviceAttach(IOService * service, IOService * provider)
3051 {
3052 IOReturn ret;
3053 OSObjectUserVars * vars;
3054 OSObject * prop;
3055 OSString * str;
3056 OSSymbolConstPtr bundleID;
3057 char execPath[1024];
3058
3059 vars = IONewZero(OSObjectUserVars, 1);
3060 service->reserved->uvars = vars;
3061
3062 vars->userServer = this;
3063 vars->userServer->retain();
3064 IOLockLock(fLock);
3065 if (-1U == fServices->getNextIndexOfObject(service, 0)) {
3066 fServices->setObject(service);
3067 }
3068 IOLockUnlock(fLock);
3069
3070 prop = service->copyProperty(gIOUserClassKey);
3071 str = OSDynamicCast(OSString, prop);
3072 if (str) {
3073 service->setName(str);
3074 }
3075 OSSafeReleaseNULL(prop);
3076
3077 prop = service->copyProperty(gIOModuleIdentifierKey);
3078 bundleID = OSDynamicCast(OSSymbol, prop);
3079 if (bundleID) {
3080 execPath[0] = 0;
3081 bool ok = OSKext::copyUserExecutablePath(bundleID, execPath, sizeof(execPath));
3082 if (ok) {
3083 ret = LoadModule(execPath);
3084 if (kIODKLogSetup & gIODKDebug) {
3085 DKLOG("%s::LoadModule 0x%x %s\n", getName(), ret, execPath);
3086 }
3087 }
3088 }
3089 OSSafeReleaseNULL(prop);
3090
3091 ret = kIOReturnSuccess;
3092
3093 return ret;
3094 }
3095
3096 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3097
3098 #define kDriverKitUCPrefix "com.apple.developer.driverkit.userclient-access."
3099
3100 IOReturn
3101 IOUserServer::serviceNewUserClient(IOService * service, task_t owningTask, void * securityID,
3102 uint32_t type, OSDictionary * properties, IOUserClient ** handler)
3103 {
3104 IOReturn ret;
3105 IOUserClient * uc;
3106 IOUserUserClient * userUC;
3107 OSDictionary * entitlements;
3108 OSObject * prop;
3109 OSObject * bundleID;
3110 bool ok;
3111
3112 *handler = NULL;
3113 ret = service->NewUserClient(type, &uc);
3114 if (kIOReturnSuccess != ret) {
3115 return ret;
3116 }
3117 userUC = OSDynamicCast(IOUserUserClient, uc);
3118 if (!userUC) {
3119 uc->terminate();
3120 OSSafeReleaseNULL(uc);
3121 return kIOReturnUnsupported;
3122 }
3123 userUC->setTask(owningTask);
3124
3125 if (!(kIODKDisableEntitlementChecking & gIODKDebug)) {
3126 entitlements = IOUserClient::copyClientEntitlements(owningTask);
3127 bundleID = service->copyProperty(gIOModuleIdentifierKey);
3128 ok = (entitlements
3129 && bundleID
3130 && (prop = entitlements->getObject(gIODriverKitUserClientEntitlementsKey)));
3131 if (ok) {
3132 bool found __block = false;
3133 ok = prop->iterateObjects(^bool (OSObject * object) {
3134 found = object->isEqualTo(bundleID);
3135 return found;
3136 });
3137 ok = found;
3138 }
3139 if (ok) {
3140 prop = userUC->copyProperty(gIOServiceDEXTEntitlementsKey);
3141 ok = checkEntitlements(entitlements, prop, NULL, NULL);
3142 }
3143 OSSafeReleaseNULL(bundleID);
3144 OSSafeReleaseNULL(entitlements);
3145 if (!ok) {
3146 DKLOG(DKS ":UC entitlements check failed\n", DKN(userUC));
3147 uc->terminate();
3148 OSSafeReleaseNULL(uc);
3149 return kIOReturnNotPermitted;
3150 }
3151 }
3152
3153 *handler = userUC;
3154
3155 return ret;
3156 }
3157
3158 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3159
3160 static IOPMPowerState
3161 sPowerStates[] = {
3162 { .version = kIOPMPowerStateVersion1,
3163 .capabilityFlags = 0,
3164 .outputPowerCharacter = 0,
3165 .inputPowerRequirement = 0},
3166 { .version = kIOPMPowerStateVersion1,
3167 .capabilityFlags = kIOPMLowPower,
3168 .outputPowerCharacter = kIOPMLowPower,
3169 .inputPowerRequirement = kIOPMLowPower},
3170 { .version = kIOPMPowerStateVersion1,
3171 .capabilityFlags = kIOPMPowerOn,
3172 .outputPowerCharacter = kIOPMPowerOn,
3173 .inputPowerRequirement = kIOPMPowerOn},
3174 };
3175
3176 IOReturn
3177 IOUserServer::setPowerState(unsigned long state, IOService * service)
3178 {
3179 if (kIODKLogPM & gIODKDebug) {
3180 DKLOG(DKS "::setPowerState(%ld) %d\n", DKN(service), state, fSystemPowerAck);
3181 }
3182 return kIOPMAckImplied;
3183 }
3184
3185 IOReturn
3186 IOUserServer::powerStateWillChangeTo(IOPMPowerFlags flags, unsigned long state, IOService * service)
3187 {
3188 IOReturn ret;
3189
3190 if (service->reserved->uvars) {
3191 if (!fSystemOff && !(kIODKDisablePM & gIODKDebug)) {
3192 service->reserved->uvars->willPower = true;
3193 if (kIODKLogPM & gIODKDebug) {
3194 DKLOG(DKS "::powerStateWillChangeTo(%ld) 0x%qx, %d\n", DKN(service), state, fPowerStates, fSystemPowerAck);
3195 }
3196 ret = service->SetPowerState(flags);
3197 if (kIOReturnSuccess == ret) {
3198 return 20 * 1000 * 1000;
3199 }
3200 }
3201 service->reserved->uvars->willPower = false;
3202 }
3203
3204 return kIOPMAckImplied;
3205 }
3206
3207 IOReturn
3208 IOUserServer::powerStateDidChangeTo(IOPMPowerFlags flags, unsigned long state, IOService * service)
3209 {
3210 unsigned int idx;
3211 bool pmAck;
3212
3213 pmAck = false;
3214 IOLockLock(fLock);
3215 idx = fServices->getNextIndexOfObject(service, 0);
3216 if (-1U == idx) {
3217 IOLockUnlock(fLock);
3218 return kIOPMAckImplied;
3219 }
3220 assert(idx <= 63);
3221
3222 if (state) {
3223 fPowerStates |= (1ULL << idx);
3224 } else {
3225 fPowerStates &= ~(1ULL << idx);
3226 }
3227 if (kIODKLogPM & gIODKDebug) {
3228 DKLOG(DKS "::powerStateDidChangeTo(%ld) 0x%qx, %d\n", DKN(service), state, fPowerStates, fSystemPowerAck);
3229 }
3230 if (!fPowerStates && (pmAck = fSystemPowerAck)) {
3231 fSystemPowerAck = false;
3232 fSystemOff = true;
3233 }
3234 IOLockUnlock(fLock);
3235
3236 if (pmAck) {
3237 IOServicePH::serverAck(this);
3238 }
3239
3240 return kIOPMAckImplied;
3241 }
3242
3243 kern_return_t
3244 IMPL(IOService, SetPowerState)
3245 {
3246 if (kIODKLogPM & gIODKDebug) {
3247 DKLOG(DKS "::SetPowerState(%d), %d\n", DKN(this), powerFlags, reserved->uvars->willPower);
3248 }
3249 if (reserved->uvars
3250 && reserved->uvars->userServer
3251 && reserved->uvars->willPower) {
3252 reserved->uvars->willPower = false;
3253 acknowledgePowerChange(reserved->uvars->userServer);
3254 return kIOReturnSuccess;
3255 }
3256 return kIOReturnNotReady;
3257 }
3258
3259 kern_return_t
3260 IMPL(IOService, ChangePowerState)
3261 {
3262 switch (powerFlags) {
3263 case kIOServicePowerCapabilityOff:
3264 changePowerStateToPriv(0);
3265 break;
3266 case kIOServicePowerCapabilityLow:
3267 changePowerStateToPriv(1);
3268 break;
3269 case kIOServicePowerCapabilityOn:
3270 changePowerStateToPriv(2);
3271 break;
3272 default:
3273 return kIOReturnBadArgument;
3274 }
3275
3276 return kIOReturnSuccess;
3277 }
3278
3279 kern_return_t
3280 IMPL(IOService, Create)
3281 {
3282 OSObject * inst;
3283 IOService * service;
3284 OSString * str;
3285 const OSSymbol * sym;
3286 OSObject * prop;
3287 OSDictionary * properties;
3288 kern_return_t ret;
3289
3290 if (provider != this) {
3291 return kIOReturnUnsupported;
3292 }
3293
3294 ret = kIOReturnUnsupported;
3295 inst = NULL;
3296 service = NULL;
3297
3298 prop = copyProperty(propertiesKey);
3299 properties = OSDynamicCast(OSDictionary, prop);
3300 assert(properties);
3301 if (properties) {
3302 str = OSDynamicCast(OSString, properties->getObject(gIOClassKey));
3303 assert(str);
3304 sym = OSSymbol::withString(str);
3305 if (sym) {
3306 inst = OSMetaClass::allocClassWithName(sym);
3307 service = OSDynamicCast(IOService, inst);
3308 if (service && service->init(properties) && service->attach(this)) {
3309 reserved->uvars->userServer->serviceAttach(service, this);
3310 service->reserved->uvars->started = true;
3311 ret = kIOReturnSuccess;
3312 *result = service;
3313 }
3314 OSSafeReleaseNULL(sym);
3315 }
3316 }
3317
3318 OSSafeReleaseNULL(prop);
3319 if (kIOReturnSuccess != ret) {
3320 OSSafeReleaseNULL(inst);
3321 }
3322
3323 return ret;
3324 }
3325
3326 kern_return_t
3327 IMPL(IOService, Terminate)
3328 {
3329 IOUserServer * us;
3330
3331 if (options) {
3332 return kIOReturnUnsupported;
3333 }
3334
3335 us = (typeof(us))thread_iokit_tls_get(0);
3336 if (!reserved->uvars
3337 || (reserved->uvars->userServer != us)) {
3338 return kIOReturnNotPermitted;
3339 }
3340 terminate(kIOServiceTerminateNeedWillTerminate);
3341
3342 return kIOReturnSuccess;
3343 }
3344
3345 kern_return_t
3346 IMPL(IOService, NewUserClient)
3347 {
3348 return kIOReturnError;
3349 }
3350
3351 kern_return_t
3352 IMPL(IOService, SearchProperty)
3353 {
3354 OSObject * object;
3355
3356 if (kIOServiceSearchPropertyParents & options) {
3357 options = kIORegistryIterateParents | kIORegistryIterateRecursively;
3358 } else {
3359 options = 0;
3360 }
3361
3362 object = copyProperty(name, IORegistryEntry::getPlane(plane), options);
3363 *property = object;
3364
3365 return object ? kIOReturnSuccess : kIOReturnNotFound;
3366 }
3367
3368 kern_return_t
3369 IMPL(IOService, CopyProviderProperties)
3370 {
3371 IOReturn ret;
3372 OSArray * result;
3373 IOService * provider;
3374
3375 result = OSArray::withCapacity(8);
3376 if (!result) {
3377 return kIOReturnNoMemory;
3378 }
3379
3380 ret = kIOReturnSuccess;
3381 for (provider = this; provider; provider = provider->getProvider()) {
3382 OSObject * obj;
3383 OSDictionary * props;
3384
3385 obj = provider->copyProperty(gIOSupportedPropertiesKey);
3386 props = OSDynamicCast(OSDictionary, obj);
3387 if (!props) {
3388 OSSafeReleaseNULL(obj);
3389 props = provider->dictionaryWithProperties();
3390 }
3391 if (!props) {
3392 ret = kIOReturnNoMemory;
3393 break;
3394 }
3395 bool __block addClass = true;
3396 if (propertyKeys) {
3397 OSDictionary * retProps;
3398 retProps = OSDictionary::withCapacity(4);
3399 addClass = false;
3400 if (!retProps) {
3401 ret = kIOReturnNoMemory;
3402 break;
3403 }
3404 propertyKeys->iterateObjects(^bool (OSObject * _key) {
3405 OSString * key = OSDynamicCast(OSString, _key);
3406 if (gIOClassKey->isEqualTo(key)) {
3407 addClass = true;
3408 return false;
3409 }
3410 retProps->setObject(key, props->getObject(key));
3411 return false;
3412 });
3413 OSSafeReleaseNULL(props);
3414 props = retProps;
3415 }
3416 if (addClass) {
3417 OSArray * classes = OSArray::withCapacity(8);
3418 if (!classes) {
3419 ret = kIOReturnNoMemory;
3420 break;
3421 }
3422 for (const OSMetaClass * meta = provider->getMetaClass(); meta; meta = meta->getSuperClass()) {
3423 classes->setObject(meta->getClassNameSymbol());
3424 }
3425 props->setObject(gIOClassKey, classes);
3426 OSSafeReleaseNULL(classes);
3427 }
3428 bool ok = result->setObject(props);
3429 props->release();
3430 if (!ok) {
3431 ret = kIOReturnNoMemory;
3432 break;
3433 }
3434 }
3435 if (kIOReturnSuccess != ret) {
3436 OSSafeReleaseNULL(result);
3437 }
3438 *properties = result;
3439 return ret;
3440 }
3441
3442 void
3443 IOUserServer::systemPower(bool powerOff)
3444 {
3445 OSArray * services;
3446
3447 if (kIODKLogPM & gIODKDebug) {
3448 DKLOG("%s::powerOff(%d) 0x%qx\n", getName(), powerOff, fPowerStates);
3449 }
3450
3451 IOLockLock(fLock);
3452 services = OSArray::withArray(fServices);
3453
3454 if (powerOff) {
3455 fSystemPowerAck = (0 != fPowerStates);
3456 if (!fSystemPowerAck) {
3457 fSystemOff = true;
3458 }
3459 IOLockUnlock(fLock);
3460
3461 if (!fSystemPowerAck) {
3462 IOServicePH::serverAck(this);
3463 } else {
3464 if (services) {
3465 services->iterateObjects(^bool (OSObject * obj) {
3466 IOService * service;
3467 service = (IOService *) obj;
3468 if (kIODKLogPM & gIODKDebug) {
3469 DKLOG("changePowerStateWithOverrideTo(" DKS ", %d)\n", DKN(service), 0);
3470 }
3471 service->reserved->uvars->powerOverride = service->getPowerState();
3472 service->changePowerStateWithOverrideTo(0, 0);
3473 return false;
3474 });
3475 }
3476 }
3477 } else {
3478 fSystemOff = false;
3479 IOLockUnlock(fLock);
3480 if (services) {
3481 services->iterateObjects(^bool (OSObject * obj) {
3482 IOService * service;
3483 service = (IOService *) obj;
3484 if (-1U != service->reserved->uvars->powerOverride) {
3485 if (kIODKLogPM & gIODKDebug) {
3486 DKLOG("changePowerStateWithOverrideTo(" DKS ", %d)\n", DKN(service), service->reserved->uvars->powerOverride);
3487 }
3488 service->changePowerStateWithOverrideTo(service->reserved->uvars->powerOverride, 0);
3489 service->reserved->uvars->powerOverride = -1U;
3490 }
3491 return false;
3492 });
3493 }
3494 }
3495 OSSafeReleaseNULL(services);
3496 }
3497
3498
3499
3500 IOReturn
3501 IOUserServer::serviceStarted(IOService * service, IOService * provider, bool result)
3502 {
3503 IOReturn ret;
3504 IOService * pmProvider;
3505
3506 DKLOG(DKS "::start(" DKS ") %s\n", DKN(service), DKN(provider), result ? "ok" : "fail");
3507
3508 if (!result) {
3509 ret = kIOReturnSuccess;
3510 return ret;
3511 }
3512
3513 if (!fRootNotifier) {
3514 ret = registerPowerDriver(this, sPowerStates, sizeof(sPowerStates) / sizeof(sPowerStates[0]));
3515 assert(kIOReturnSuccess == ret);
3516 IOServicePH::serverAdd(this);
3517 fRootNotifier = true;
3518 }
3519
3520 if (!(kIODKDisablePM & gIODKDebug) && !service->pm_vars) {
3521 service->PMinit();
3522 ret = service->registerPowerDriver(this, sPowerStates, sizeof(sPowerStates) / sizeof(sPowerStates[0]));
3523 assert(kIOReturnSuccess == ret);
3524
3525 pmProvider = service;
3526 while (pmProvider && !pmProvider->inPlane(gIOPowerPlane)) {
3527 pmProvider = pmProvider->getProvider();
3528 }
3529 if (pmProvider) {
3530 OSObject * prop;
3531 OSString * str;
3532 prop = pmProvider->copyProperty("non-removable");
3533 if (prop) {
3534 str = OSDynamicCast(OSString, prop);
3535 if (str && str->isEqualTo("yes")) {
3536 pmProvider = NULL;
3537 }
3538 prop->release();
3539 }
3540 }
3541 if (pmProvider) {
3542 IOLockLock(fLock);
3543 unsigned int idx = fServices->getNextIndexOfObject(service, 0);
3544 assert(idx <= 63);
3545 fPowerStates |= (1ULL << idx);
3546 IOLockUnlock(fLock);
3547
3548 pmProvider->joinPMtree(service);
3549 service->reserved->uvars->userServerPM = true;
3550 }
3551 }
3552
3553 service->registerInterestedDriver(this);
3554 service->reserved->uvars->started = true;
3555
3556 return kIOReturnSuccess;
3557 }
3558
3559
3560 IOReturn
3561 IOUserServer::serviceOpen(IOService * provider, IOService * client)
3562 {
3563 OSObjectUserVars * uvars;
3564
3565 uvars = client->reserved->uvars;
3566 if (!uvars->openProviders) {
3567 uvars->openProviders = OSArray::withObjects((const OSObject **) &provider, 1);
3568 } else if (-1U == uvars->openProviders->getNextIndexOfObject(client, 0)) {
3569 uvars->openProviders->setObject(provider);
3570 }
3571
3572 return kIOReturnSuccess;
3573 }
3574
3575 IOReturn
3576 IOUserServer::serviceClose(IOService * provider, IOService * client)
3577 {
3578 OSObjectUserVars * uvars;
3579 unsigned int idx;
3580
3581 uvars = client->reserved->uvars;
3582 if (!uvars->openProviders) {
3583 return kIOReturnNotOpen;
3584 }
3585 idx = uvars->openProviders->getNextIndexOfObject(client, 0);
3586 if (-1U == idx) {
3587 return kIOReturnNotOpen;
3588 }
3589 uvars->openProviders->removeObject(idx);
3590
3591 return kIOReturnSuccess;
3592 }
3593
3594
3595 IOReturn
3596 IOUserServer::serviceStop(IOService * service, IOService *)
3597 {
3598 IOReturn ret;
3599 uint32_t idx, queueAlloc;
3600 OSObjectUserVars * uvars;
3601
3602 IOLockLock(fLock);
3603 idx = fServices->getNextIndexOfObject(service, 0);
3604 if (-1U != idx) {
3605 fServices->removeObject(idx);
3606 uvars = service->reserved->uvars;
3607 uvars->stopped = true;
3608 }
3609 IOLockUnlock(fLock);
3610
3611 if (-1U == idx) {
3612 return kIOReturnSuccess;
3613 }
3614
3615 if (uvars->queueArray && uvars->userMeta) {
3616 queueAlloc = 1;
3617 if (uvars->userMeta->queueNames) {
3618 queueAlloc += uvars->userMeta->queueNames->count;
3619 }
3620 for (idx = 0; idx < queueAlloc; idx++) {
3621 OSSafeReleaseNULL(uvars->queueArray[idx]);
3622 }
3623 IOSafeDeleteNULL(uvars->queueArray, IODispatchQueue *, queueAlloc);
3624 }
3625
3626 (void) service->deRegisterInterestedDriver(this);
3627 if (uvars->userServerPM) {
3628 service->PMstop();
3629 }
3630
3631 ret = kIOReturnSuccess;
3632 return ret;
3633 }
3634
3635 void
3636 IOUserServer::serviceFree(IOService * service)
3637 {
3638 OSObjectUserVars * uvars;
3639
3640 uvars = service->reserved->uvars;
3641 if (!uvars) {
3642 return;
3643 }
3644 OSSafeReleaseNULL(uvars->userServer);
3645 IOSafeDeleteNULL(service->reserved->uvars, OSObjectUserVars, 1);
3646 }
3647
3648 void
3649 IOUserServer::serviceWillTerminate(IOService * client, IOService * provider, IOOptionBits options)
3650 {
3651 IOReturn ret;
3652 bool willTerminate;
3653
3654 willTerminate = false;
3655 if (client->lockForArbitration(true)) {
3656 if (!client->reserved->uvars->serverDied
3657 && !client->reserved->uvars->willTerminate) {
3658 client->reserved->uvars->willTerminate = true;
3659 willTerminate = true;
3660 }
3661 client->unlockForArbitration();
3662 }
3663
3664 if (willTerminate) {
3665 ret = client->Stop(provider);
3666 if (kIOReturnSuccess != ret) {
3667 ret = client->IOService::Stop(provider);
3668 }
3669 }
3670 }
3671
3672 void
3673 IOUserServer::serviceDidTerminate(IOService * client, IOService * provider, IOOptionBits options, bool * defer)
3674 {
3675 if (client->lockForArbitration(true)) {
3676 client->reserved->uvars->didTerminate = true;
3677 if (!client->reserved->uvars->serverDied
3678 && !client->reserved->uvars->stopped) {
3679 *defer = true;
3680 }
3681 client->unlockForArbitration();
3682 }
3683 }
3684
3685 void
3686 IOUserServer::serviceDidStop(IOService * client, IOService * provider)
3687 {
3688 bool complete;
3689 OSArray * closeArray;
3690
3691 complete = false;
3692 closeArray = NULL;
3693
3694 if (client->lockForArbitration(true)) {
3695 if (client->reserved->uvars
3696 && client->reserved->uvars->willTerminate
3697 && !client->reserved->uvars->stopped) {
3698 client->reserved->uvars->stopped = true;
3699 complete = client->reserved->uvars->didTerminate;
3700 }
3701
3702 if (client->reserved->uvars) {
3703 closeArray = client->reserved->uvars->openProviders;
3704 client->reserved->uvars->openProviders = NULL;
3705 }
3706 client->unlockForArbitration();
3707 if (closeArray) {
3708 closeArray->iterateObjects(^bool (OSObject * obj) {
3709 IOService * toClose;
3710 toClose = OSDynamicCast(IOService, obj);
3711 if (toClose) {
3712 DKLOG(DKS ":force close (" DKS ")\n", DKN(client), DKN(toClose));
3713 toClose->close(client);
3714 }
3715 return false;
3716 });
3717 closeArray->release();
3718 }
3719 }
3720 if (complete) {
3721 bool defer = false;
3722 client->didTerminate(provider, 0, &defer);
3723 }
3724 }
3725
3726 kern_return_t
3727 IMPL(IOService, Stop)
3728 {
3729 IOUserServer::serviceDidStop(this, provider);
3730
3731 return kIOReturnSuccess;
3732 }
3733
3734 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3735
3736 #undef super
3737 #define super IOUserClient
3738
3739 OSDefineMetaClassAndStructors(IOUserUserClient, IOUserClient)
3740
3741 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3742
3743 IOReturn
3744 IOUserUserClient::setTask(task_t task)
3745 {
3746 task_reference(task);
3747 fTask = task;
3748
3749 return kIOReturnSuccess;
3750 }
3751
3752 void
3753 IOUserUserClient::stop(IOService * provider)
3754 {
3755 if (fTask) {
3756 task_deallocate(fTask);
3757 fTask = NULL;
3758 }
3759 super::stop(provider);
3760 }
3761
3762 IOReturn
3763 IOUserUserClient::clientClose(void)
3764 {
3765 terminate(kIOServiceTerminateNeedWillTerminate);
3766 return kIOReturnSuccess;
3767 }
3768
3769 IOReturn
3770 IOUserUserClient::setProperties(OSObject * properties)
3771 {
3772 IOReturn ret = kIOReturnUnsupported;
3773 return ret;
3774 }
3775
3776 struct IOUserUserClientActionRef {
3777 OSAsyncReference64 asyncRef;
3778 };
3779
3780 void
3781 IMPL(IOUserClient, KernelCompletion)
3782 {
3783 IOUserUserClientActionRef * ref;
3784
3785 ref = (typeof(ref))action->GetReference();
3786
3787 IOUserClient::sendAsyncResult64(ref->asyncRef, status, (io_user_reference_t *) asyncData, asyncDataCount);
3788 }
3789
3790 kern_return_t
3791 IMPL(IOUserClient, _ExternalMethod)
3792 {
3793 return kIOReturnUnsupported;
3794 }
3795
3796 IOReturn
3797 IOUserUserClient::clientMemoryForType(UInt32 type,
3798 IOOptionBits * koptions,
3799 IOMemoryDescriptor ** kmemory)
3800 {
3801 IOReturn kr;
3802 uint64_t options;
3803 IOMemoryDescriptor * memory;
3804
3805 kr = CopyClientMemoryForType(type, &options, &memory);
3806
3807 *koptions = 0;
3808 *kmemory = NULL;
3809 if (kIOReturnSuccess != kr) {
3810 return kr;
3811 }
3812
3813 if (kIOUserClientMemoryReadOnly & options) {
3814 *koptions |= kIOMapReadOnly;
3815 }
3816 *kmemory = memory;
3817
3818 return kr;
3819 }
3820
3821 IOReturn
3822 IOUserUserClient::externalMethod(uint32_t selector, IOExternalMethodArguments * args,
3823 IOExternalMethodDispatch * dispatch, OSObject * target, void * reference)
3824 {
3825 IOReturn kr;
3826 OSData * structureInput;
3827 OSData * structureOutput;
3828 size_t copylen;
3829 uint64_t structureOutputSize;
3830 OSAction * action;
3831 IOUserUserClientActionRef * ref;
3832
3833 kr = kIOReturnUnsupported;
3834 structureInput = NULL;
3835 action = NULL;
3836
3837 if (args->structureInputSize) {
3838 structureInput = OSData::withBytesNoCopy((void *) args->structureInput, args->structureInputSize);
3839 }
3840
3841 if (MACH_PORT_NULL != args->asyncWakePort) {
3842 kr = CreateActionKernelCompletion(sizeof(IOUserUserClientActionRef), &action);
3843 assert(KERN_SUCCESS == kr);
3844 ref = (typeof(ref))action->GetReference();
3845 bcopy(args->asyncReference, &ref->asyncRef[0], args->asyncReferenceCount * sizeof(ref->asyncRef[0]));
3846 }
3847
3848 if (args->structureVariableOutputData) {
3849 structureOutputSize = kIOUserClientVariableStructureSize;
3850 } else if (args->structureOutputDescriptor) {
3851 structureOutputSize = args->structureOutputDescriptor->getLength();
3852 } else {
3853 structureOutputSize = args->structureOutputSize;
3854 }
3855
3856 kr = _ExternalMethod(selector, &args->scalarInput[0], args->scalarInputCount,
3857 structureInput, args->structureInputDescriptor,
3858 args->scalarOutput, &args->scalarOutputCount,
3859 structureOutputSize, &structureOutput, args->structureOutputDescriptor,
3860 action);
3861
3862 OSSafeReleaseNULL(structureInput);
3863 OSSafeReleaseNULL(action);
3864
3865 if (kIOReturnSuccess != kr) {
3866 return kr;
3867 }
3868 if (structureOutput) {
3869 if (args->structureVariableOutputData) {
3870 *args->structureVariableOutputData = structureOutput;
3871 } else {
3872 copylen = structureOutput->getLength();
3873 if (copylen > args->structureOutputSize) {
3874 kr = kIOReturnBadArgument;
3875 } else {
3876 bcopy((const void *) structureOutput->getBytesNoCopy(), args->structureOutput, copylen);
3877 }
3878 OSSafeReleaseNULL(structureOutput);
3879 }
3880 }
3881
3882 return kr;
3883 }
3884
3885 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */