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