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