1 /*
2 * Copyright (c) 1998-2021 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/IOKernelReportStructs.h>
33 #include <IOKit/IOUserClient.h>
34 #include <IOKit/IOService.h>
35 #include <IOKit/IORegistryEntry.h>
36 #include <IOKit/IOCatalogue.h>
37 #include <IOKit/IOMemoryDescriptor.h>
38 #include <IOKit/IOBufferMemoryDescriptor.h>
39 #include <IOKit/IOSubMemoryDescriptor.h>
40 #include <IOKit/IOMultiMemoryDescriptor.h>
41 #include <IOKit/IOMapper.h>
42 #include <IOKit/IOLib.h>
43 #include <IOKit/IOHibernatePrivate.h>
44 #include <IOKit/IOBSD.h>
45 #include <IOKit/system.h>
46 #include <IOKit/IOUserServer.h>
47 #include <IOKit/IOInterruptEventSource.h>
48 #include <IOKit/IOTimerEventSource.h>
49 #include <IOKit/pwr_mgt/RootDomain.h>
50 #include <libkern/c++/OSAllocation.h>
51 #include <libkern/c++/OSKext.h>
52 #include <libkern/c++/OSSharedPtr.h>
53 #include <libkern/OSDebug.h>
54 #include <libkern/Block.h>
55 #include <kern/cs_blobs.h>
56 #include <kern/thread_call.h>
57 #include <os/atomic_private.h>
58 #include <sys/proc.h>
59 #include <sys/reboot.h>
60 #include <sys/codesign.h>
61 #include "IOKitKernelInternal.h"
62
63 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
64
65 #include <DriverKit/IODispatchQueue.h>
66 #include <DriverKit/OSObject.h>
67 #include <DriverKit/OSAction.h>
68 #include <DriverKit/IODispatchSource.h>
69 #include <DriverKit/IOInterruptDispatchSource.h>
70 #include <DriverKit/IOService.h>
71 #include <DriverKit/IOMemoryDescriptor.h>
72 #include <DriverKit/IOBufferMemoryDescriptor.h>
73 #include <DriverKit/IOMemoryMap.h>
74 #include <DriverKit/IODataQueueDispatchSource.h>
75 #include <DriverKit/IOServiceNotificationDispatchSource.h>
76 #include <DriverKit/IOServiceStateNotificationDispatchSource.h>
77 #include <DriverKit/IOEventLink.h>
78 #include <DriverKit/IOWorkGroup.h>
79 #include <DriverKit/IOUserServer.h>
80
81 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
82
83 #include <System/IODataQueueDispatchSourceShared.h>
84
85 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
86
87 TUNABLE(SInt64, gIODKDebug, "dk", kIODKEnable);
88
89 #if DEBUG || DEVELOPMENT
90 TUNABLE(bool, disable_dext_crash_reboot, "disable_dext_crash_reboot", 0);
91 #endif /* DEBUG || DEVELOPMENT */
92
93 static OSString * gIOSystemStateSleepDescriptionKey;
94 static const OSSymbol * gIOSystemStateSleepDescriptionReasonKey;
95 static const OSSymbol * gIOSystemStateSleepDescriptionHibernateStateKey;
96
97 static OSString * gIOSystemStateWakeDescriptionKey;
98 static const OSSymbol * gIOSystemStateWakeDescriptionWakeReasonKey;
99
100 static OSString * gIOSystemStateHaltDescriptionKey;
101 static const OSSymbol * gIOSystemStateHaltDescriptionHaltStateKey;
102
103 static OSString * gIOSystemStatePowerSourceDescriptionKey;
104 static const OSSymbol * gIOSystemStatePowerSourceDescriptionACAttachedKey;
105
106 extern bool gInUserspaceReboot;
107
108 extern void iokit_clear_registered_ports(task_t task);
109
110 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
111
112 struct IOPStrings;
113
114 class OSUserMetaClass : public OSObject
115 {
116 OSDeclareDefaultStructors(OSUserMetaClass);
117 public:
118 const OSSymbol * name;
119 const OSMetaClass * meta;
120 OSUserMetaClass * superMeta;
121
122 queue_chain_t link;
123
124 OSClassDescription * description;
125 IOPStrings * queueNames;
126 uint32_t methodCount;
127 uint64_t * methods;
128
129 virtual void free() override;
130 virtual kern_return_t Dispatch(const IORPC rpc) APPLE_KEXT_OVERRIDE;
131 };
132 OSDefineMetaClassAndStructors(OSUserMetaClass, OSObject);
133
134 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
135
136 class IOUserService : public IOService
137 {
138 friend class IOService;
139
140 OSDeclareDefaultStructors(IOUserService)
141
142 virtual bool
143 start(IOService * provider) APPLE_KEXT_OVERRIDE;
144 };
145
146 OSDefineMetaClassAndStructors(IOUserService, IOService)
147
148 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
149
150 class IOUserUserClient : public IOUserClient
151 {
152 OSDeclareDefaultStructors(IOUserUserClient);
153 public:
154 task_t fTask;
155 OSDictionary * fWorkGroups;
156 OSDictionary * fEventLinks;
157 IOLock * fLock;
158
159 IOReturn setTask(task_t task);
160 IOReturn eventlinkConfigurationTrap(void * p1, void * p2, void * p3, void * p4, void * p5, void * p6);
161 IOReturn workgroupConfigurationTrap(void * p1, void * p2, void * p3, void * p4, void * p5, void * p6);
162
163 virtual bool init( OSDictionary * dictionary ) APPLE_KEXT_OVERRIDE;
164 virtual void free() APPLE_KEXT_OVERRIDE;
165 virtual void stop(IOService * provider) APPLE_KEXT_OVERRIDE;
166 virtual IOReturn clientClose(void) APPLE_KEXT_OVERRIDE;
167 virtual IOReturn setProperties(OSObject * properties) APPLE_KEXT_OVERRIDE;
168 virtual IOReturn externalMethod(uint32_t selector, IOExternalMethodArguments * args,
169 IOExternalMethodDispatch * dispatch, OSObject * target, void * reference) APPLE_KEXT_OVERRIDE;
170 virtual IOReturn clientMemoryForType(UInt32 type,
171 IOOptionBits * options,
172 IOMemoryDescriptor ** memory) APPLE_KEXT_OVERRIDE;
173 virtual IOExternalTrap * getTargetAndTrapForIndex( IOService **targetP, UInt32 index ) APPLE_KEXT_OVERRIDE;
174 };
175
176 OSDefineMetaClassAndStructors(IOUserServerCheckInToken, OSObject);
177 OSDefineMetaClassAndStructors(_IOUserServerCheckInCancellationHandler, OSObject);
178
179 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
180
181
182 bool
start(IOService * provider)183 IOUserService::start(IOService * provider)
184 {
185 bool ok = true;
186 IOReturn ret;
187
188 ret = Start(provider);
189 if (kIOReturnSuccess != ret) {
190 return false;
191 }
192
193 return ok;
194 }
195
196 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
197
198 #undef super
199
200 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
201
202 struct IODispatchQueue_IVars {
203 IOUserServer * userServer;
204 IODispatchQueue * queue;
205 queue_chain_t link;
206 uint64_t tid;
207
208 mach_port_t serverPort;
209 };
210
211 struct OSAction_IVars {
212 OSObject * target;
213 uint64_t targetmsgid;
214 uint64_t msgid;
215 IOUserServer * userServer;
216 OSActionAbortedHandler abortedHandler;
217 OSString * typeName;
218 void * reference;
219 size_t referenceSize;
220 bool aborted;
221 };
222
223 struct IOWorkGroup_IVars {
224 IOUserServer * userServer;
225 OSString * name;
226 IOUserUserClient * userClient;
227 };
228
229 struct IOEventLink_IVars {
230 IOUserServer * userServer;
231 OSString * name;
232 IOUserUserClient * userClient;
233 };
234
235 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
236
237 kern_return_t
GetRegistryEntryID_Impl(uint64_t * registryEntryID)238 IOService::GetRegistryEntryID_Impl(
239 uint64_t * registryEntryID)
240 {
241 IOReturn ret = kIOReturnSuccess;
242
243 *registryEntryID = getRegistryEntryID();
244
245 return ret;
246 }
247
248 kern_return_t
SetName_Impl(const char * name)249 IOService::SetName_Impl(
250 const char * name)
251 {
252 IOReturn ret = kIOReturnSuccess;
253
254 setName(name);
255
256 return ret;
257 }
258
259 kern_return_t
CopyName_Impl(OSString ** name)260 IOService::CopyName_Impl(
261 OSString ** name)
262 {
263 const OSString * str = copyName();
264 *name = __DECONST(OSString *, str);
265 return str ? kIOReturnSuccess : kIOReturnError;
266 }
267
268
269 kern_return_t
Start_Impl(IOService * provider)270 IOService::Start_Impl(
271 IOService * provider)
272 {
273 IOReturn ret = kIOReturnSuccess;
274 return ret;
275 }
276
277
278 IOReturn
UpdateReport_Impl(OSData * channels,uint32_t action,uint32_t * outElementCount,uint64_t offset,uint64_t capacity,IOMemoryDescriptor * buffer)279 IOService::UpdateReport_Impl(OSData *channels, uint32_t action,
280 uint32_t *outElementCount,
281 uint64_t offset, uint64_t capacity,
282 IOMemoryDescriptor *buffer)
283 {
284 return kIOReturnUnsupported;
285 }
286
287 IOReturn
ConfigureReport_Impl(OSData * channels,uint32_t action,uint32_t * outCount)288 IOService::ConfigureReport_Impl(OSData *channels, uint32_t action, uint32_t *outCount)
289 {
290 return kIOReturnUnsupported;
291 }
292
293 // adapt old signature of configureReport to the iig-friendly signature of ConfigureReport
294 IOReturn
_ConfigureReport(IOReportChannelList * channelList,IOReportConfigureAction action,void * result,void * destination)295 IOService::_ConfigureReport(IOReportChannelList *channelList,
296 IOReportConfigureAction action,
297 void *result,
298 void *destination)
299 {
300 if (action != kIOReportEnable && action != kIOReportGetDimensions && action != kIOReportDisable) {
301 return kIOReturnUnsupported;
302 }
303 static_assert(sizeof(IOReportChannelList) == 8);
304 static_assert(sizeof(IOReportChannel) == 16);
305 unsigned int size_of_channels;
306 bool overflow = os_mul_and_add_overflow(channelList->nchannels, sizeof(IOReportChannel), sizeof(IOReportChannelList), &size_of_channels);
307 if (overflow) {
308 return kIOReturnOverrun;
309 }
310 OSSharedPtr<OSData> sp_channels(OSData::withBytesNoCopy(channelList, size_of_channels), libkern::no_retain);
311 if (!sp_channels) {
312 return kIOReturnNoMemory;
313 }
314 int *resultp = (int*) result;
315 uint32_t count = 0;
316 IOReturn r = ConfigureReport(sp_channels.get(), action, &count);
317 int new_result;
318 overflow = os_add_overflow(*resultp, count, &new_result);
319 if (overflow) {
320 return kIOReturnOverrun;
321 }
322 *resultp = new_result;
323 return r;
324 }
325
326 // adapt old signature of updateReport to the iig-friendly signature of UpdateReport
327 IOReturn
_UpdateReport(IOReportChannelList * channelList,IOReportUpdateAction action,void * result,void * destination)328 IOService::_UpdateReport(IOReportChannelList *channelList,
329 IOReportUpdateAction action,
330 void *result,
331 void *destination)
332 {
333 if (action != kIOReportCopyChannelData) {
334 return kIOReturnUnsupported;
335 }
336 unsigned int size_of_channels;
337 bool overflow = os_mul_and_add_overflow(channelList->nchannels, sizeof(IOReportChannel), sizeof(IOReportChannelList), &size_of_channels);
338 if (overflow) {
339 return kIOReturnOverrun;
340 }
341 OSSharedPtr<OSData> sp_channels(OSData::withBytesNoCopy(channelList, size_of_channels), libkern::no_retain);
342 if (!sp_channels) {
343 return kIOReturnNoMemory;
344 }
345 int *resultp = (int*) result;
346 uint32_t count = 0;
347 auto buffer = (IOBufferMemoryDescriptor*) destination;
348 uint64_t length = buffer->getLength();
349 buffer->setLength(buffer->getCapacity());
350 IOReturn r = UpdateReport(sp_channels.get(), action, &count, length, buffer->getCapacity() - length, buffer);
351 int new_result;
352 overflow = os_add_overflow(*resultp, count, &new_result);
353 size_t new_length;
354 overflow = overflow || os_mul_and_add_overflow(count, sizeof(IOReportElement), length, &new_length);
355 if (overflow || new_length > buffer->getCapacity()) {
356 buffer->setLength(length);
357 return kIOReturnOverrun;
358 }
359 *resultp = new_result;
360 buffer->setLength(new_length);
361 return r;
362 }
363
364
365 IOReturn
SetLegend_Impl(OSArray * legend,bool is_public)366 IOService::SetLegend_Impl(OSArray *legend, bool is_public)
367 {
368 bool ok = setProperty(kIOReportLegendKey, legend);
369 ok = ok && setProperty(kIOReportLegendPublicKey, is_public);
370 return ok ? kIOReturnSuccess : kIOReturnError;
371 }
372
373
374 kern_return_t
RegisterService_Impl()375 IOService::RegisterService_Impl()
376 {
377 IOReturn ret = kIOReturnSuccess;
378 bool started;
379
380 IOUserServer *us = (typeof(us))thread_iokit_tls_get(0);
381 if (reserved != NULL && reserved->uvars != NULL && reserved->uvars->userServer == us) {
382 started = reserved->uvars->started;
383 } else {
384 // assume started
385 started = true;
386 }
387
388 if (OSDynamicCast(IOUserServer, this) != NULL || started) {
389 registerService(kIOServiceAsynchronous);
390 } else {
391 assert(reserved != NULL && reserved->uvars != NULL);
392 reserved->uvars->deferredRegisterService = true;
393 }
394
395 return ret;
396 }
397
398 kern_return_t
CopyDispatchQueue_Impl(const char * name,IODispatchQueue ** queue)399 IOService::CopyDispatchQueue_Impl(
400 const char * name,
401 IODispatchQueue ** queue)
402 {
403 IODispatchQueue * result;
404 IOService * service;
405 IOReturn ret;
406 uint32_t index;
407
408 if (!reserved->uvars) {
409 return kIOReturnError;
410 }
411
412 ret = kIOReturnNotFound;
413 index = -1U;
414 if (!strcmp("Default", name)) {
415 index = 0;
416 } else if (reserved->uvars->userMeta
417 && reserved->uvars->userMeta->queueNames) {
418 index = reserved->uvars->userServer->stringArrayIndex(reserved->uvars->userMeta->queueNames, name);
419 if (index != -1U) {
420 index++;
421 }
422 }
423 if (index == -1U) {
424 if ((service = getProvider())) {
425 ret = service->CopyDispatchQueue(name, queue);
426 }
427 } else {
428 result = reserved->uvars->queueArray[index];
429 if (result) {
430 result->retain();
431 *queue = result;
432 ret = kIOReturnSuccess;
433 }
434 }
435
436 return ret;
437 }
438
439 kern_return_t
CreateDefaultDispatchQueue_Impl(IODispatchQueue ** queue)440 IOService::CreateDefaultDispatchQueue_Impl(
441 IODispatchQueue ** queue)
442 {
443 return kIOReturnError;
444 }
445
446 kern_return_t
CoreAnalyticsSendEvent_Impl(uint64_t options,OSString * eventName,OSDictionary * eventPayload)447 IOService::CoreAnalyticsSendEvent_Impl(
448 uint64_t options,
449 OSString * eventName,
450 OSDictionary * eventPayload)
451 {
452 kern_return_t ret;
453
454 if (NULL == gIOCoreAnalyticsSendEventProc) {
455 // perhaps save for later?
456 return kIOReturnNotReady;
457 }
458
459 ret = (*gIOCoreAnalyticsSendEventProc)(options, eventName, eventPayload);
460
461 return ret;
462 }
463
464 kern_return_t
SetDispatchQueue_Impl(const char * name,IODispatchQueue * queue)465 IOService::SetDispatchQueue_Impl(
466 const char * name,
467 IODispatchQueue * queue)
468 {
469 IOReturn ret = kIOReturnSuccess;
470 uint32_t index;
471
472 if (!reserved->uvars) {
473 return kIOReturnError;
474 }
475
476 if (kIODKLogSetup & gIODKDebug) {
477 DKLOG(DKS "::SetDispatchQueue(%s)\n", DKN(this), name);
478 }
479 queue->ivars->userServer = reserved->uvars->userServer;
480 index = -1U;
481 if (!strcmp("Default", name)) {
482 index = 0;
483 } else if (reserved->uvars->userMeta
484 && reserved->uvars->userMeta->queueNames) {
485 index = reserved->uvars->userServer->stringArrayIndex(reserved->uvars->userMeta->queueNames, name);
486 if (index != -1U) {
487 index++;
488 }
489 }
490 if (index == -1U) {
491 ret = kIOReturnBadArgument;
492 } else {
493 reserved->uvars->queueArray[index] = queue;
494 queue->retain();
495 }
496
497 return ret;
498 }
499
500 IOService *
GetProvider() const501 IOService::GetProvider() const
502 {
503 return getProvider();
504 }
505
506 kern_return_t
SetProperties_Impl(OSDictionary * properties)507 IOService::SetProperties_Impl(
508 OSDictionary * properties)
509 {
510 IOUserServer * us;
511 OSDictionary * dict;
512 IOReturn ret;
513
514 us = (typeof(us))thread_iokit_tls_get(0);
515 dict = OSDynamicCast(OSDictionary, properties);
516 if (NULL == us) {
517 if (!dict) {
518 return kIOReturnBadArgument;
519 }
520 bool ok __block = true;
521 dict->iterateObjects(^bool (const OSSymbol * key, OSObject * value) {
522 ok = setProperty(key, value);
523 return !ok;
524 });
525 ret = ok ? kIOReturnSuccess : kIOReturnNotWritable;
526 return ret;
527 }
528
529 ret = setProperties(properties);
530
531 if (kIOReturnUnsupported == ret) {
532 if (dict && reserved->uvars && (reserved->uvars->userServer == us)) {
533 ret = runPropertyActionBlock(^IOReturn (void) {
534 OSDictionary * userProps;
535 IOReturn ret;
536
537 userProps = OSDynamicCast(OSDictionary, getProperty(gIOUserServicePropertiesKey));
538 if (userProps) {
539 userProps = (typeof(userProps))userProps->copyCollection();
540 } else {
541 userProps = OSDictionary::withCapacity(4);
542 }
543 if (!userProps) {
544 ret = kIOReturnNoMemory;
545 } else {
546 bool ok = userProps->merge(dict);
547 if (ok) {
548 ok = setProperty(gIOUserServicePropertiesKey, userProps);
549 }
550 OSSafeReleaseNULL(userProps);
551 ret = ok ? kIOReturnSuccess : kIOReturnNotWritable;
552 }
553 return ret;
554 });
555 }
556 }
557
558 return ret;
559 }
560
561 kern_return_t
RemoveProperty_Impl(OSString * propertyName)562 IOService::RemoveProperty_Impl(OSString * propertyName)
563 {
564 IOUserServer * us = (IOUserServer *)thread_iokit_tls_get(0);
565 IOReturn ret = kIOReturnUnsupported;
566
567 if (NULL == propertyName) {
568 return kIOReturnUnsupported;
569 }
570 if (NULL == us) {
571 removeProperty(propertyName);
572 return kIOReturnSuccess;
573 }
574 if (reserved && reserved->uvars && reserved->uvars->userServer == us) {
575 ret = runPropertyActionBlock(^IOReturn (void) {
576 OSDictionary * userProps;
577 userProps = OSDynamicCast(OSDictionary, getProperty(gIOUserServicePropertiesKey));
578 if (userProps) {
579 userProps = (OSDictionary *)userProps->copyCollection();
580 if (!userProps) {
581 return kIOReturnNoMemory;
582 }
583 userProps->removeObject(propertyName);
584 bool ok = setProperty(gIOUserServicePropertiesKey, userProps);
585 OSSafeReleaseNULL(userProps);
586 return ok ? kIOReturnSuccess : kIOReturnNotWritable;
587 } else {
588 return kIOReturnNotFound;
589 }
590 });
591 }
592 return ret;
593 }
594
595 kern_return_t
CopyProperties_Local(OSDictionary ** properties)596 IOService::CopyProperties_Local(
597 OSDictionary ** properties)
598 {
599 OSDictionary * props;
600 OSDictionary * userProps;
601
602 props = dictionaryWithProperties();
603 userProps = OSDynamicCast(OSDictionary, props->getObject(gIOUserServicePropertiesKey));
604 if (userProps) {
605 props->merge(userProps);
606 props->removeObject(gIOUserServicePropertiesKey);
607 }
608
609 *properties = props;
610
611 return props ? kIOReturnSuccess : kIOReturnNoMemory;
612 }
613
614 kern_return_t
CopyProperties_Impl(OSDictionary ** properties)615 IOService::CopyProperties_Impl(
616 OSDictionary ** properties)
617 {
618 return CopyProperties_Local(properties);
619 }
620
621 kern_return_t
RequireMaxBusStall_Impl(uint64_t u64ns)622 IOService::RequireMaxBusStall_Impl(
623 uint64_t u64ns)
624 {
625 IOReturn ret;
626 UInt32 ns;
627
628 if (os_convert_overflow(u64ns, &ns)) {
629 return kIOReturnBadArgument;
630 }
631 ret = requireMaxBusStall(ns);
632
633 return ret;
634 }
635
636 #if PRIVATE_WIFI_ONLY
637 kern_return_t
UserSetProperties_Impl(OSContainer * properties)638 IOService::UserSetProperties_Impl(
639 OSContainer * properties)
640 {
641 return kIOReturnUnsupported;
642 }
643
644 kern_return_t
SendIOMessageServicePropertyChange_Impl(void)645 IOService::SendIOMessageServicePropertyChange_Impl(void)
646 {
647 return messageClients(kIOMessageServicePropertyChange);
648 }
649 #endif /* PRIVATE_WIFI_ONLY */
650
651 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
652
653 kern_return_t
_CopyState_Impl(_IOMDPrivateState * state)654 IOMemoryDescriptor::_CopyState_Impl(
655 _IOMDPrivateState * state)
656 {
657 IOReturn ret;
658
659 state->length = _length;
660 state->options = _flags;
661
662 ret = kIOReturnSuccess;
663
664 return ret;
665 }
666
667 kern_return_t
GetLength(uint64_t * returnLength)668 IOMemoryDescriptor::GetLength(uint64_t * returnLength)
669 {
670 *returnLength = getLength();
671
672 return kIOReturnSuccess;
673 }
674
675 kern_return_t
CreateMapping_Impl(uint64_t options,uint64_t address,uint64_t offset,uint64_t length,uint64_t alignment,IOMemoryMap ** map)676 IOMemoryDescriptor::CreateMapping_Impl(
677 uint64_t options,
678 uint64_t address,
679 uint64_t offset,
680 uint64_t length,
681 uint64_t alignment,
682 IOMemoryMap ** map)
683 {
684 IOReturn ret;
685 IOMemoryMap * resultMap;
686 IOOptionBits koptions;
687 mach_vm_address_t atAddress;
688
689 ret = kIOReturnSuccess;
690 koptions = 0;
691 resultMap = NULL;
692
693 if (kIOMemoryMapFixedAddress & options) {
694 atAddress = address;
695 koptions = 0;
696 } else {
697 switch (kIOMemoryMapGuardedMask & options) {
698 default:
699 case kIOMemoryMapGuardedDefault:
700 koptions |= kIOMapGuardedSmall;
701 break;
702 case kIOMemoryMapGuardedNone:
703 break;
704 case kIOMemoryMapGuardedSmall:
705 koptions |= kIOMapGuardedSmall;
706 break;
707 case kIOMemoryMapGuardedLarge:
708 koptions |= kIOMapGuardedLarge;
709 break;
710 }
711 atAddress = 0;
712 koptions |= kIOMapAnywhere;
713 }
714
715 if ((kIOMemoryMapReadOnly & options) || (kIODirectionOut == getDirection())) {
716 if (!reserved || (current_task() != reserved->creator)) {
717 koptions |= kIOMapReadOnly;
718 }
719 }
720
721 switch (0xFF00 & options) {
722 case kIOMemoryMapCacheModeDefault:
723 koptions |= kIOMapDefaultCache;
724 break;
725 case kIOMemoryMapCacheModeInhibit:
726 koptions |= kIOMapInhibitCache;
727 break;
728 case kIOMemoryMapCacheModeCopyback:
729 koptions |= kIOMapCopybackCache;
730 break;
731 case kIOMemoryMapCacheModeWriteThrough:
732 koptions |= kIOMapWriteThruCache;
733 break;
734 default:
735 ret = kIOReturnBadArgument;
736 }
737
738 if (kIOReturnSuccess == ret) {
739 resultMap = createMappingInTask(current_task(), atAddress, koptions, offset, length);
740 if (!resultMap) {
741 ret = kIOReturnError;
742 }
743 }
744
745 *map = resultMap;
746
747 return ret;
748 }
749
750 kern_return_t
CreateSubMemoryDescriptor_Impl(uint64_t memoryDescriptorCreateOptions,uint64_t offset,uint64_t length,IOMemoryDescriptor * ofDescriptor,IOMemoryDescriptor ** memory)751 IOMemoryDescriptor::CreateSubMemoryDescriptor_Impl(
752 uint64_t memoryDescriptorCreateOptions,
753 uint64_t offset,
754 uint64_t length,
755 IOMemoryDescriptor * ofDescriptor,
756 IOMemoryDescriptor ** memory)
757 {
758 IOReturn ret;
759 IOMemoryDescriptor * iomd;
760 IOByteCount mdOffset;
761 IOByteCount mdLength;
762 IOByteCount mdEnd;
763
764 if (!ofDescriptor) {
765 return kIOReturnBadArgument;
766 }
767 if (memoryDescriptorCreateOptions & ~kIOMemoryDirectionOutIn) {
768 return kIOReturnBadArgument;
769 }
770 if (os_convert_overflow(offset, &mdOffset)) {
771 return kIOReturnBadArgument;
772 }
773 if (os_convert_overflow(length, &mdLength)) {
774 return kIOReturnBadArgument;
775 }
776 if (os_add_overflow(mdOffset, mdLength, &mdEnd)) {
777 return kIOReturnBadArgument;
778 }
779 if (mdEnd > ofDescriptor->getLength()) {
780 return kIOReturnBadArgument;
781 }
782
783 iomd = IOSubMemoryDescriptor::withSubRange(
784 ofDescriptor, mdOffset, mdLength, (IOOptionBits) memoryDescriptorCreateOptions);
785
786 if (iomd) {
787 ret = kIOReturnSuccess;
788 *memory = iomd;
789 } else {
790 ret = kIOReturnNoMemory;
791 *memory = NULL;
792 }
793
794 return ret;
795 }
796
797 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
798
799 kern_return_t
CreateWithMemoryDescriptors_Impl(uint64_t memoryDescriptorCreateOptions,uint32_t withDescriptorsCount,IOMemoryDescriptor ** const withDescriptors,IOMemoryDescriptor ** memory)800 IOMemoryDescriptor::CreateWithMemoryDescriptors_Impl(
801 uint64_t memoryDescriptorCreateOptions,
802 uint32_t withDescriptorsCount,
803 IOMemoryDescriptor ** const withDescriptors,
804 IOMemoryDescriptor ** memory)
805 {
806 IOReturn ret;
807 IOMemoryDescriptor * iomd;
808
809 if (!withDescriptors) {
810 return kIOReturnBadArgument;
811 }
812 if (!withDescriptorsCount) {
813 return kIOReturnBadArgument;
814 }
815 if (memoryDescriptorCreateOptions & ~kIOMemoryDirectionOutIn) {
816 return kIOReturnBadArgument;
817 }
818
819 for (unsigned int idx = 0; idx < withDescriptorsCount; idx++) {
820 if (NULL == withDescriptors[idx]) {
821 return kIOReturnBadArgument;
822 }
823 }
824
825 iomd = IOMultiMemoryDescriptor::withDescriptors(withDescriptors, withDescriptorsCount,
826 (IODirection) memoryDescriptorCreateOptions, false);
827
828 if (iomd) {
829 ret = kIOReturnSuccess;
830 *memory = iomd;
831 } else {
832 ret = kIOReturnNoMemory;
833 *memory = NULL;
834 }
835
836 return ret;
837 }
838
839 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
840
841 kern_return_t
CreateMemoryDescriptorFromClient_Impl(uint64_t memoryDescriptorCreateOptions,uint32_t segmentsCount,const IOAddressSegment segments[32],IOMemoryDescriptor ** memory)842 IOUserClient::CreateMemoryDescriptorFromClient_Impl(
843 uint64_t memoryDescriptorCreateOptions,
844 uint32_t segmentsCount,
845 const IOAddressSegment segments[32],
846 IOMemoryDescriptor ** memory)
847 {
848 IOReturn ret;
849 IOMemoryDescriptor * iomd;
850 IOOptionBits mdOptions;
851 IOUserUserClient * me;
852 IOAddressRange * ranges;
853
854 me = OSDynamicCast(IOUserUserClient, this);
855 if (!me) {
856 return kIOReturnBadArgument;
857 }
858 if (!me->fTask) {
859 return kIOReturnNotReady;
860 }
861
862 mdOptions = kIOMemoryThreadSafe;
863 if (kIOMemoryDirectionOut & memoryDescriptorCreateOptions) {
864 mdOptions |= kIODirectionOut;
865 }
866 if (kIOMemoryDirectionIn & memoryDescriptorCreateOptions) {
867 mdOptions |= kIODirectionIn;
868 }
869 if (!(kIOMemoryDisableCopyOnWrite & memoryDescriptorCreateOptions)) {
870 mdOptions |= kIOMemoryMapCopyOnWrite;
871 }
872
873 static_assert(sizeof(IOAddressRange) == sizeof(IOAddressSegment));
874 ranges = __DECONST(IOAddressRange *, &segments[0]);
875
876 iomd = IOMemoryDescriptor::withAddressRanges(
877 ranges, segmentsCount,
878 mdOptions, me->fTask);
879
880 if (iomd) {
881 ret = kIOReturnSuccess;
882 *memory = iomd;
883 } else {
884 ret = kIOReturnNoMemory;
885 *memory = NULL;
886 }
887
888 return ret;
889 }
890
891 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
892
893 kern_return_t
_CopyState_Impl(_IOMemoryMapPrivateState * state)894 IOMemoryMap::_CopyState_Impl(
895 _IOMemoryMapPrivateState * state)
896 {
897 IOReturn ret;
898
899 state->offset = fOffset;
900 state->length = getLength();
901 state->address = getAddress();
902 state->options = getMapOptions();
903
904 ret = kIOReturnSuccess;
905
906 return ret;
907 }
908
909 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
910
911 kern_return_t
Create_Impl(uint64_t options,uint64_t capacity,uint64_t alignment,IOBufferMemoryDescriptor ** memory)912 IOBufferMemoryDescriptor::Create_Impl(
913 uint64_t options,
914 uint64_t capacity,
915 uint64_t alignment,
916 IOBufferMemoryDescriptor ** memory)
917 {
918 IOReturn ret;
919 IOOptionBits bmdOptions;
920 IOBufferMemoryDescriptor * bmd;
921 IOMemoryDescriptorReserved * reserved;
922
923 if (options & ~((uint64_t) kIOMemoryDirectionOutIn)) {
924 // no other options currently defined
925 return kIOReturnBadArgument;
926 }
927 bmdOptions = (options & kIOMemoryDirectionOutIn) | kIOMemoryKernelUserShared | kIOMemoryThreadSafe;
928 bmd = IOBufferMemoryDescriptor::inTaskWithOptions(
929 kernel_task, bmdOptions, capacity, alignment);
930
931 *memory = bmd;
932
933 if (!bmd) {
934 return kIOReturnNoMemory;
935 }
936
937 reserved = bmd->getKernelReserved();
938 reserved->creator = current_task();
939 task_reference(reserved->creator);
940
941 ret = kIOReturnSuccess;
942
943 return ret;
944 }
945
946 kern_return_t
SetLength_Impl(uint64_t length)947 IOBufferMemoryDescriptor::SetLength_Impl(
948 uint64_t length)
949 {
950 setLength(length);
951 return kIOReturnSuccess;
952 }
953
954
955 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
956
957 kern_return_t
Create_Impl(IOService * device,uint64_t options,const IODMACommandSpecification * specification,IODMACommand ** command)958 IODMACommand::Create_Impl(
959 IOService * device,
960 uint64_t options,
961 const IODMACommandSpecification * specification,
962 IODMACommand ** command)
963 {
964 IOReturn ret;
965 IODMACommand * dma;
966 IODMACommand::SegmentOptions segmentOptions;
967 IOMapper * mapper;
968
969 if (options & ~((uint64_t) kIODMACommandCreateNoOptions)) {
970 // no other options currently defined
971 return kIOReturnBadArgument;
972 }
973
974 if (os_convert_overflow(specification->maxAddressBits, &segmentOptions.fNumAddressBits)) {
975 return kIOReturnBadArgument;
976 }
977 segmentOptions.fMaxSegmentSize = 0;
978 segmentOptions.fMaxTransferSize = 0;
979 segmentOptions.fAlignment = 1;
980 segmentOptions.fAlignmentLength = 1;
981 segmentOptions.fAlignmentInternalSegments = 1;
982 segmentOptions.fStructSize = sizeof(segmentOptions);
983
984 mapper = IOMapper::copyMapperForDevice(device);
985
986 dma = IODMACommand::withSpecification(
987 kIODMACommandOutputHost64,
988 &segmentOptions,
989 kIODMAMapOptionDextOwner |
990 kIODMAMapOptionMapped,
991 mapper,
992 NULL);
993
994 OSSafeReleaseNULL(mapper);
995 *command = dma;
996
997 if (!dma) {
998 return kIOReturnNoMemory;
999 }
1000 ret = kIOReturnSuccess;
1001
1002 return ret;
1003 }
1004
1005 #define fInternalState reserved
1006
1007 kern_return_t
PrepareForDMA_Impl(uint64_t options,IOMemoryDescriptor * memory,uint64_t offset,uint64_t length,uint64_t * flags,uint32_t * segmentsCount,IOAddressSegment * segments)1008 IODMACommand::PrepareForDMA_Impl(
1009 uint64_t options,
1010 IOMemoryDescriptor * memory,
1011 uint64_t offset,
1012 uint64_t length,
1013 uint64_t * flags,
1014 uint32_t * segmentsCount,
1015 IOAddressSegment * segments)
1016 {
1017 IOReturn ret;
1018 uint64_t lflags, mdFlags;
1019 UInt32 numSegments;
1020 UInt64 genOffset;
1021
1022 if (options & ~((uint64_t) kIODMACommandPrepareForDMANoOptions)) {
1023 // no other options currently defined
1024 return kIOReturnBadArgument;
1025 }
1026
1027 if (memory == NULL) {
1028 return kIOReturnBadArgument;
1029 }
1030
1031 assert(fInternalState->fDextLock);
1032 IOLockLock(fInternalState->fDextLock);
1033
1034 // uses IOMD direction
1035 ret = memory->prepare();
1036 if (kIOReturnSuccess != ret) {
1037 goto exit;
1038 }
1039
1040 ret = setMemoryDescriptor(memory, false);
1041 if (kIOReturnSuccess != ret) {
1042 memory->complete();
1043 goto exit;
1044 }
1045
1046 ret = prepare(offset, length);
1047 if (kIOReturnSuccess != ret) {
1048 clearMemoryDescriptor(false);
1049 memory->complete();
1050 goto exit;
1051 }
1052
1053 static_assert(sizeof(IODMACommand::Segment64) == sizeof(IOAddressSegment));
1054
1055 numSegments = *segmentsCount;
1056 genOffset = 0;
1057 ret = genIOVMSegments(&genOffset, segments, &numSegments);
1058
1059 if (kIOReturnSuccess != ret) {
1060 clearMemoryDescriptor(true);
1061 memory->complete();
1062 goto exit;
1063 }
1064
1065 mdFlags = fMemory->getFlags();
1066 lflags = 0;
1067 if (kIODirectionOut & mdFlags) {
1068 lflags |= kIOMemoryDirectionOut;
1069 }
1070 if (kIODirectionIn & mdFlags) {
1071 lflags |= kIOMemoryDirectionIn;
1072 }
1073 *flags = lflags;
1074 *segmentsCount = numSegments;
1075
1076 exit:
1077 IOLockUnlock(fInternalState->fDextLock);
1078
1079 return ret;
1080 }
1081
1082 kern_return_t
CompleteDMA_Impl(uint64_t options)1083 IODMACommand::CompleteDMA_Impl(
1084 uint64_t options)
1085 {
1086 IOReturn ret, completeRet;
1087 IOMemoryDescriptor * md;
1088
1089 if (options & ~((uint64_t) kIODMACommandCompleteDMANoOptions)) {
1090 // no other options currently defined
1091 return kIOReturnBadArgument;
1092 }
1093
1094 assert(fInternalState->fDextLock);
1095 IOLockLock(fInternalState->fDextLock);
1096
1097 if (!fInternalState->fPrepared) {
1098 ret = kIOReturnNotReady;
1099 goto exit;
1100 }
1101
1102 md = __DECONST(IOMemoryDescriptor *, fMemory);
1103 if (md) {
1104 md->retain();
1105 }
1106
1107 ret = clearMemoryDescriptor(true);
1108
1109 if (md) {
1110 completeRet = md->complete();
1111 OSSafeReleaseNULL(md);
1112 if (kIOReturnSuccess == ret) {
1113 ret = completeRet;
1114 }
1115 }
1116 exit:
1117 IOLockUnlock(fInternalState->fDextLock);
1118
1119 return ret;
1120 }
1121
1122 kern_return_t
GetPreparation_Impl(uint64_t * offset,uint64_t * length,IOMemoryDescriptor ** memory)1123 IODMACommand::GetPreparation_Impl(
1124 uint64_t * offset,
1125 uint64_t * length,
1126 IOMemoryDescriptor ** memory)
1127 {
1128 IOReturn ret;
1129 IOMemoryDescriptor * md;
1130
1131 if (!fActive) {
1132 return kIOReturnNotReady;
1133 }
1134
1135 ret = getPreparedOffsetAndLength(offset, length);
1136 if (kIOReturnSuccess != ret) {
1137 return ret;
1138 }
1139
1140 if (memory) {
1141 md = __DECONST(IOMemoryDescriptor *, fMemory);
1142 *memory = md;
1143 if (!md) {
1144 ret = kIOReturnNotReady;
1145 } else {
1146 md->retain();
1147 }
1148 }
1149 return ret;
1150 }
1151
1152 kern_return_t
PerformOperation_Impl(uint64_t options,uint64_t dmaOffset,uint64_t length,uint64_t dataOffset,IOMemoryDescriptor * data)1153 IODMACommand::PerformOperation_Impl(
1154 uint64_t options,
1155 uint64_t dmaOffset,
1156 uint64_t length,
1157 uint64_t dataOffset,
1158 IOMemoryDescriptor * data)
1159 {
1160 IOReturn ret;
1161 OSDataAllocation<uint8_t> buffer;
1162 UInt64 copiedDMA;
1163 IOByteCount mdOffset, mdLength, copied;
1164
1165 if (options & ~((uint64_t)
1166 (kIODMACommandPerformOperationOptionRead
1167 | kIODMACommandPerformOperationOptionWrite
1168 | kIODMACommandPerformOperationOptionZero))) {
1169 // no other options currently defined
1170 return kIOReturnBadArgument;
1171 }
1172
1173 if (!fActive) {
1174 return kIOReturnNotReady;
1175 }
1176 if (os_convert_overflow(dataOffset, &mdOffset)) {
1177 return kIOReturnBadArgument;
1178 }
1179 if (os_convert_overflow(length, &mdLength)) {
1180 return kIOReturnBadArgument;
1181 }
1182 if (length > fMemory->getLength()) {
1183 return kIOReturnBadArgument;
1184 }
1185 buffer = OSDataAllocation<uint8_t>(length, OSAllocateMemory);
1186 if (!buffer) {
1187 return kIOReturnNoMemory;
1188 }
1189
1190 switch (options) {
1191 case kIODMACommandPerformOperationOptionZero:
1192 bzero(buffer.data(), length);
1193 copiedDMA = writeBytes(dmaOffset, buffer.data(), length);
1194 if (copiedDMA != length) {
1195 ret = kIOReturnUnderrun;
1196 break;
1197 }
1198 ret = kIOReturnSuccess;
1199 break;
1200
1201 case kIODMACommandPerformOperationOptionRead:
1202 case kIODMACommandPerformOperationOptionWrite:
1203
1204 if (!data) {
1205 ret = kIOReturnBadArgument;
1206 break;
1207 }
1208 if (length > data->getLength()) {
1209 ret = kIOReturnBadArgument;
1210 break;
1211 }
1212 if (kIODMACommandPerformOperationOptionWrite == options) {
1213 copied = data->readBytes(mdOffset, buffer.data(), mdLength);
1214 if (copied != mdLength) {
1215 ret = kIOReturnUnderrun;
1216 break;
1217 }
1218 copiedDMA = writeBytes(dmaOffset, buffer.data(), length);
1219 if (copiedDMA != length) {
1220 ret = kIOReturnUnderrun;
1221 break;
1222 }
1223 } else { /* kIODMACommandPerformOperationOptionRead */
1224 copiedDMA = readBytes(dmaOffset, buffer.data(), length);
1225 if (copiedDMA != length) {
1226 ret = kIOReturnUnderrun;
1227 break;
1228 }
1229 copied = data->writeBytes(mdOffset, buffer.data(), mdLength);
1230 if (copied != mdLength) {
1231 ret = kIOReturnUnderrun;
1232 break;
1233 }
1234 }
1235 ret = kIOReturnSuccess;
1236 break;
1237 default:
1238 ret = kIOReturnBadArgument;
1239 break;
1240 }
1241
1242 return ret;
1243 }
1244
1245
1246 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1247
1248 static kern_return_t
OSActionCreateWithTypeNameInternal(OSObject * target,uint64_t targetmsgid,uint64_t msgid,size_t referenceSize,OSString * typeName,bool fromKernel,OSAction ** action)1249 OSActionCreateWithTypeNameInternal(OSObject * target, uint64_t targetmsgid, uint64_t msgid, size_t referenceSize, OSString * typeName, bool fromKernel, OSAction ** action)
1250 {
1251 OSAction * inst = NULL;
1252 void * reference = NULL; // must release
1253 const OSSymbol *sym = NULL; // must release
1254 OSObject *obj = NULL; // must release
1255 const OSMetaClass *actionMetaClass = NULL; // do not release
1256 kern_return_t ret;
1257
1258 if (fromKernel && typeName) {
1259 /* The action is being constructed in the kernel with a type name */
1260 sym = OSSymbol::withString(typeName);
1261 actionMetaClass = OSMetaClass::getMetaClassWithName(sym);
1262 if (actionMetaClass && actionMetaClass->getSuperClass() == OSTypeID(OSAction)) {
1263 obj = actionMetaClass->alloc();
1264 if (!obj) {
1265 ret = kIOReturnNoMemory;
1266 goto finish;
1267 }
1268 inst = OSDynamicCast(OSAction, obj);
1269 obj = NULL; // prevent release
1270 assert(inst); // obj is a subclass of OSAction so the dynamic cast should always work
1271 } else {
1272 DKLOG("Attempted to create action object with type \"%s\" which does not inherit from OSAction\n", typeName->getCStringNoCopy());
1273 ret = kIOReturnBadArgument;
1274 goto finish;
1275 }
1276 } else {
1277 inst = OSTypeAlloc(OSAction);
1278 if (!inst) {
1279 ret = kIOReturnNoMemory;
1280 goto finish;
1281 }
1282 }
1283
1284 if (referenceSize != 0) {
1285 reference = IONewZeroData(uint8_t, referenceSize);
1286 if (reference == NULL) {
1287 ret = kIOReturnNoMemory;
1288 goto finish;
1289 }
1290 }
1291
1292 inst->ivars = IONewZero(OSAction_IVars, 1);
1293 if (!inst->ivars) {
1294 ret = kIOReturnNoMemory;
1295 goto finish;
1296 }
1297 if (target) {
1298 target->retain();
1299 if (!fromKernel && !OSDynamicCast(IOService, target)) {
1300 IOUserServer * us;
1301 us = (typeof(us))thread_iokit_tls_get(0);
1302 inst->ivars->userServer = OSDynamicCast(IOUserServer, us);
1303 assert(inst->ivars->userServer);
1304 inst->ivars->userServer->retain();
1305 }
1306 }
1307 inst->ivars->target = target;
1308 inst->ivars->targetmsgid = targetmsgid;
1309 inst->ivars->msgid = msgid;
1310
1311 inst->ivars->reference = reference;
1312 inst->ivars->referenceSize = referenceSize;
1313 reference = NULL; // prevent release
1314
1315 if (typeName) {
1316 typeName->retain();
1317 }
1318 inst->ivars->typeName = typeName;
1319
1320 *action = inst;
1321 inst = NULL; // prevent release
1322 ret = kIOReturnSuccess;
1323
1324 finish:
1325 OSSafeReleaseNULL(obj);
1326 OSSafeReleaseNULL(sym);
1327 OSSafeReleaseNULL(inst);
1328 if (reference) {
1329 IODeleteData(reference, uint8_t, referenceSize);
1330 }
1331
1332 return ret;
1333 }
1334
1335 kern_return_t
Create(OSAction_Create_Args)1336 OSAction::Create(OSAction_Create_Args)
1337 {
1338 return OSAction::CreateWithTypeName(target, targetmsgid, msgid, referenceSize, NULL, action);
1339 }
1340
1341 kern_return_t
CreateWithTypeName(OSAction_CreateWithTypeName_Args)1342 OSAction::CreateWithTypeName(OSAction_CreateWithTypeName_Args)
1343 {
1344 return OSActionCreateWithTypeNameInternal(target, targetmsgid, msgid, referenceSize, typeName, true, action);
1345 }
1346
1347 kern_return_t
Create_Impl(OSObject * target,uint64_t targetmsgid,uint64_t msgid,size_t referenceSize,OSAction ** action)1348 OSAction::Create_Impl(
1349 OSObject * target,
1350 uint64_t targetmsgid,
1351 uint64_t msgid,
1352 size_t referenceSize,
1353 OSAction ** action)
1354 {
1355 return OSAction::CreateWithTypeName_Impl(target, targetmsgid, msgid, referenceSize, NULL, action);
1356 }
1357
1358 kern_return_t
CreateWithTypeName_Impl(OSObject * target,uint64_t targetmsgid,uint64_t msgid,size_t referenceSize,OSString * typeName,OSAction ** action)1359 OSAction::CreateWithTypeName_Impl(
1360 OSObject * target,
1361 uint64_t targetmsgid,
1362 uint64_t msgid,
1363 size_t referenceSize,
1364 OSString * typeName,
1365 OSAction ** action)
1366 {
1367 return OSActionCreateWithTypeNameInternal(target, targetmsgid, msgid, referenceSize, typeName, false, action);
1368 }
1369
1370 void
free()1371 OSAction::free()
1372 {
1373 if (ivars) {
1374 if (ivars->abortedHandler) {
1375 Block_release(ivars->abortedHandler);
1376 ivars->abortedHandler = NULL;
1377 }
1378 OSSafeReleaseNULL(ivars->target);
1379 OSSafeReleaseNULL(ivars->typeName);
1380 OSSafeReleaseNULL(ivars->userServer);
1381 if (ivars->reference) {
1382 assert(ivars->referenceSize > 0);
1383 IODeleteData(ivars->reference, uint8_t, ivars->referenceSize);
1384 }
1385 IOSafeDeleteNULL(ivars, OSAction_IVars, 1);
1386 }
1387 return super::free();
1388 }
1389
1390 void *
GetReference()1391 OSAction::GetReference()
1392 {
1393 assert(ivars && ivars->referenceSize && ivars->reference);
1394 return ivars->reference;
1395 }
1396
1397 kern_return_t
SetAbortedHandler(OSActionAbortedHandler handler)1398 OSAction::SetAbortedHandler(OSActionAbortedHandler handler)
1399 {
1400 ivars->abortedHandler = Block_copy(handler);
1401 return kIOReturnSuccess;
1402 }
1403
1404 void
Aborted_Impl(void)1405 OSAction::Aborted_Impl(void)
1406 {
1407 if (!os_atomic_cmpxchg(&ivars->aborted, false, true, relaxed)) {
1408 // already aborted
1409 return;
1410 }
1411 if (ivars->abortedHandler) {
1412 ivars->abortedHandler();
1413 }
1414 }
1415
1416 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1417
1418 struct IODispatchSource_IVars {
1419 queue_chain_t link;
1420 IODispatchSource * source;
1421 IOUserServer * server;
1422 IODispatchQueue_IVars * queue;
1423 bool enabled;
1424 };
1425
1426 bool
init()1427 IODispatchSource::init()
1428 {
1429 if (!super::init()) {
1430 return false;
1431 }
1432
1433 ivars = IOMallocType(IODispatchSource_IVars);
1434
1435 ivars->source = this;
1436
1437 return true;
1438 }
1439
1440 void
free()1441 IODispatchSource::free()
1442 {
1443 IOFreeType(ivars, IODispatchSource_IVars);
1444 super::free();
1445 }
1446
1447 kern_return_t
SetEnable_Impl(bool enable)1448 IODispatchSource::SetEnable_Impl(
1449 bool enable)
1450 {
1451 return SetEnableWithCompletion(enable, NULL);
1452 }
1453
1454 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1455
1456 struct IOInterruptDispatchSource_IVars {
1457 IOService * provider;
1458 uint32_t intIndex;
1459 uint32_t flags;
1460 int interruptType;
1461 IOSimpleLock * lock;
1462 thread_t waiter;
1463 uint64_t count;
1464 uint64_t time;
1465 OSAction * action;
1466 bool enable;
1467 bool canceled;
1468 };
1469
1470 static void
IOInterruptDispatchSourceInterrupt(OSObject * target,void * refCon,IOService * nub,int source)1471 IOInterruptDispatchSourceInterrupt(OSObject * target, void * refCon,
1472 IOService * nub, int source )
1473 {
1474 IOInterruptDispatchSource_IVars * ivars = (typeof(ivars))refCon;
1475 IOInterruptState is;
1476
1477 is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1478 ivars->count++;
1479 ivars->time = (kIOInterruptSourceContinuousTime & ivars->flags)
1480 ? mach_continuous_time() : mach_absolute_time();
1481 if (ivars->waiter) {
1482 thread_wakeup_thread((event_t) ivars, ivars->waiter);
1483 ivars->waiter = NULL;
1484 }
1485 if (kIOInterruptTypeLevel & ivars->interruptType) {
1486 ivars->provider->disableInterrupt(ivars->intIndex);
1487 }
1488 IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1489 }
1490
1491 kern_return_t
Create_Impl(IOService * provider,uint32_t indexAndFlags,IODispatchQueue * queue,IOInterruptDispatchSource ** source)1492 IOInterruptDispatchSource::Create_Impl(
1493 IOService * provider,
1494 uint32_t indexAndFlags,
1495 IODispatchQueue * queue,
1496 IOInterruptDispatchSource ** source)
1497 {
1498 IOReturn ret;
1499 IOInterruptDispatchSource * inst;
1500 uint32_t index;
1501 uint32_t flags;
1502
1503 index = indexAndFlags & kIOInterruptSourceIndexMask;
1504 flags = indexAndFlags & ~kIOInterruptSourceIndexMask;
1505
1506 inst = OSTypeAlloc(IOInterruptDispatchSource);
1507 if (!inst->init()) {
1508 inst->free();
1509 return kIOReturnNoMemory;
1510 }
1511
1512 inst->ivars->lock = IOSimpleLockAlloc();
1513
1514 ret = provider->getInterruptType(index, &inst->ivars->interruptType);
1515 if (kIOReturnSuccess != ret) {
1516 OSSafeReleaseNULL(inst);
1517 return ret;
1518 }
1519 ret = provider->registerInterrupt(index, inst, IOInterruptDispatchSourceInterrupt, inst->ivars);
1520 if (kIOReturnSuccess == ret) {
1521 inst->ivars->intIndex = index;
1522 inst->ivars->flags = flags;
1523 inst->ivars->provider = provider;
1524 inst->ivars->provider->retain();
1525 *source = inst;
1526 }
1527 return ret;
1528 }
1529
1530 kern_return_t
GetInterruptType_Impl(IOService * provider,uint32_t index,uint64_t * interruptType)1531 IOInterruptDispatchSource::GetInterruptType_Impl(
1532 IOService * provider,
1533 uint32_t index,
1534 uint64_t * interruptType)
1535 {
1536 IOReturn ret;
1537 int type;
1538
1539 *interruptType = 0;
1540 ret = provider->getInterruptType(index, &type);
1541 if (kIOReturnSuccess == ret) {
1542 *interruptType = type;
1543 }
1544
1545 return ret;
1546 }
1547
1548 bool
init()1549 IOInterruptDispatchSource::init()
1550 {
1551 if (!super::init()) {
1552 return false;
1553 }
1554 ivars = IOMallocType(IOInterruptDispatchSource_IVars);
1555
1556 return true;
1557 }
1558
1559 void
free()1560 IOInterruptDispatchSource::free()
1561 {
1562 IOReturn ret;
1563
1564 if (ivars && ivars->provider) {
1565 ret = ivars->provider->unregisterInterrupt(ivars->intIndex);
1566 assert(kIOReturnSuccess == ret);
1567 ivars->provider->release();
1568 }
1569
1570 if (ivars && ivars->lock) {
1571 IOSimpleLockFree(ivars->lock);
1572 }
1573
1574 IOFreeType(ivars, IOInterruptDispatchSource_IVars);
1575
1576 super::free();
1577 }
1578
1579 kern_return_t
SetHandler_Impl(OSAction * action)1580 IOInterruptDispatchSource::SetHandler_Impl(
1581 OSAction * action)
1582 {
1583 IOReturn ret;
1584 OSAction * oldAction;
1585
1586 oldAction = (typeof(oldAction))ivars->action;
1587 if (oldAction && OSCompareAndSwapPtr(oldAction, NULL, &ivars->action)) {
1588 oldAction->release();
1589 }
1590 action->retain();
1591 ivars->action = action;
1592
1593 ret = kIOReturnSuccess;
1594
1595 return ret;
1596 }
1597
1598 kern_return_t
SetEnableWithCompletion_Impl(bool enable,IODispatchSourceCancelHandler handler)1599 IOInterruptDispatchSource::SetEnableWithCompletion_Impl(
1600 bool enable,
1601 IODispatchSourceCancelHandler handler)
1602 {
1603 IOReturn ret;
1604 IOInterruptState is;
1605
1606 if (enable == ivars->enable) {
1607 return kIOReturnSuccess;
1608 }
1609
1610 if (enable) {
1611 is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1612 ivars->enable = enable;
1613 IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1614 ret = ivars->provider->enableInterrupt(ivars->intIndex);
1615 } else {
1616 ret = ivars->provider->disableInterrupt(ivars->intIndex);
1617 is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1618 ivars->enable = enable;
1619 IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1620 }
1621
1622 return ret;
1623 }
1624
1625 kern_return_t
Cancel_Impl(IODispatchSourceCancelHandler handler)1626 IOInterruptDispatchSource::Cancel_Impl(
1627 IODispatchSourceCancelHandler handler)
1628 {
1629 IOInterruptState is;
1630
1631 is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1632 ivars->canceled = true;
1633 if (ivars->waiter) {
1634 thread_wakeup_thread((event_t) ivars, ivars->waiter);
1635 ivars->waiter = NULL;
1636 }
1637 IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1638
1639 return kIOReturnSuccess;
1640 }
1641
1642 kern_return_t
CheckForWork_Impl(const IORPC rpc,bool synchronous)1643 IOInterruptDispatchSource::CheckForWork_Impl(
1644 const IORPC rpc,
1645 bool synchronous)
1646 {
1647 IOReturn ret = kIOReturnNotReady;
1648 IOInterruptState is;
1649 bool willWait;
1650 bool canceled;
1651 wait_result_t waitResult;
1652 uint64_t icount;
1653 uint64_t itime;
1654 thread_t self;
1655
1656 self = current_thread();
1657 icount = 0;
1658 do {
1659 willWait = false;
1660 is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1661 canceled = ivars->canceled;
1662 if (!canceled) {
1663 if ((icount = ivars->count)) {
1664 itime = ivars->time;
1665 ivars->count = 0;
1666 waitResult = THREAD_AWAKENED;
1667 } else if (synchronous) {
1668 assert(NULL == ivars->waiter);
1669 ivars->waiter = self;
1670 waitResult = assert_wait((event_t) ivars, THREAD_INTERRUPTIBLE);
1671 }
1672 willWait = (synchronous && (waitResult == THREAD_WAITING));
1673 if (willWait && (kIOInterruptTypeLevel & ivars->interruptType) && ivars->enable) {
1674 IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1675 ivars->provider->enableInterrupt(ivars->intIndex);
1676 } else {
1677 IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1678 }
1679 } else {
1680 IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1681 }
1682 if (willWait) {
1683 waitResult = thread_block(THREAD_CONTINUE_NULL);
1684 if (THREAD_INTERRUPTED == waitResult) {
1685 is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1686 ivars->waiter = NULL;
1687 IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1688 canceled = true;
1689 break;
1690 }
1691 }
1692 } while (synchronous && !icount && !canceled);
1693
1694 if (icount && ivars->action) {
1695 ret = InterruptOccurred(rpc, ivars->action, icount, itime);
1696 }
1697
1698 return ret;
1699 }
1700
1701 void
InterruptOccurred_Impl(OSAction * action,uint64_t count,uint64_t time)1702 IOInterruptDispatchSource::InterruptOccurred_Impl(
1703 OSAction * action,
1704 uint64_t count,
1705 uint64_t time)
1706 {
1707 }
1708
1709 kern_return_t
GetLastInterrupt_Impl(uint64_t * pCount,uint64_t * pTime)1710 IOInterruptDispatchSource::GetLastInterrupt_Impl(
1711 uint64_t * pCount,
1712 uint64_t * pTime)
1713 {
1714 IOInterruptState is;
1715 uint64_t count, time;
1716
1717 is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1718 count = ivars->count;
1719 time = ivars->time;
1720 IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1721
1722 if (pCount) {
1723 *pCount = count;
1724 }
1725 if (pTime) {
1726 *pTime = time;
1727 }
1728 return kIOReturnSuccess;
1729 }
1730
1731 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1732
1733 enum {
1734 kIOServiceNotificationTypeCount = kIOServiceNotificationTypeLast + 1,
1735 };
1736
1737 struct IOServiceNotificationDispatchSource_IVars {
1738 OSObject * serverName;
1739 OSAction * action;
1740 IOLock * lock;
1741 IONotifier * notifier;
1742 OSDictionary * interestNotifiers;
1743 OSBoundedArray<OSArray *, kIOServiceNotificationTypeCount> pending;
1744 bool enable;
1745 };
1746
1747 kern_return_t
Create_Impl(OSDictionary * matching,uint64_t options,IODispatchQueue * queue,IOServiceNotificationDispatchSource ** notification)1748 IOServiceNotificationDispatchSource::Create_Impl(
1749 OSDictionary * matching,
1750 uint64_t options,
1751 IODispatchQueue * queue,
1752 IOServiceNotificationDispatchSource ** notification)
1753 {
1754 IOUserServer * us;
1755 IOReturn ret;
1756 IOServiceNotificationDispatchSource * inst;
1757
1758 inst = OSTypeAlloc(IOServiceNotificationDispatchSource);
1759 if (!inst->init()) {
1760 OSSafeReleaseNULL(inst);
1761 return kIOReturnNoMemory;
1762 }
1763
1764 us = (typeof(us))thread_iokit_tls_get(0);
1765 assert(OSDynamicCast(IOUserServer, us));
1766 if (!us) {
1767 OSSafeReleaseNULL(inst);
1768 return kIOReturnError;
1769 }
1770 inst->ivars->serverName = us->copyProperty(gIOUserServerNameKey);
1771 if (!inst->ivars->serverName) {
1772 OSSafeReleaseNULL(inst);
1773 return kIOReturnNoMemory;
1774 }
1775
1776 inst->ivars->lock = IOLockAlloc();
1777 if (!inst->ivars->lock) {
1778 OSSafeReleaseNULL(inst);
1779 return kIOReturnNoMemory;
1780 }
1781 for (uint32_t idx = 0; idx < kIOServiceNotificationTypeCount; idx++) {
1782 inst->ivars->pending[idx] = OSArray::withCapacity(4);
1783 if (!inst->ivars->pending[idx]) {
1784 OSSafeReleaseNULL(inst);
1785 return kIOReturnNoMemory;
1786 }
1787 }
1788 inst->ivars->interestNotifiers = OSDictionary::withCapacity(4);
1789 if (!inst->ivars->interestNotifiers) {
1790 OSSafeReleaseNULL(inst);
1791 return kIOReturnNoMemory;
1792 }
1793
1794 inst->ivars->notifier = IOService::addMatchingNotification(gIOMatchedNotification, matching, 0 /*priority*/,
1795 ^bool (IOService * newService, IONotifier * notifier) {
1796 bool notifyReady = false;
1797 IONotifier * interest;
1798 OSObject * serverName;
1799 bool okToUse;
1800
1801 serverName = newService->copyProperty(gIOUserServerNameKey);
1802 okToUse = (serverName && inst->ivars->serverName->isEqualTo(serverName));
1803 OSSafeReleaseNULL(serverName);
1804 if (!okToUse) {
1805 return false;
1806 }
1807
1808 IOLockLock(inst->ivars->lock);
1809 notifyReady = (0 == inst->ivars->pending[kIOServiceNotificationTypeMatched]->getCount());
1810 inst->ivars->pending[kIOServiceNotificationTypeMatched]->setObject(newService);
1811 IOLockUnlock(inst->ivars->lock);
1812
1813 interest = newService->registerInterest(gIOGeneralInterest,
1814 ^IOReturn (uint32_t messageType, IOService * provider,
1815 void * messageArgument, size_t argSize) {
1816 IONotifier * interest;
1817 bool notifyReady = false;
1818
1819 switch (messageType) {
1820 case kIOMessageServiceIsTerminated:
1821 IOLockLock(inst->ivars->lock);
1822 notifyReady = (0 == inst->ivars->pending[kIOServiceNotificationTypeTerminated]->getCount());
1823 inst->ivars->pending[kIOServiceNotificationTypeTerminated]->setObject(provider);
1824 if (inst->ivars->interestNotifiers != NULL) {
1825 interest = (typeof(interest))inst->ivars->interestNotifiers->getObject((const OSSymbol *) newService);
1826 assert(interest);
1827 interest->remove();
1828 inst->ivars->interestNotifiers->removeObject((const OSSymbol *) newService);
1829 }
1830 IOLockUnlock(inst->ivars->lock);
1831 break;
1832 default:
1833 break;
1834 }
1835 if (notifyReady && inst->ivars->action) {
1836 inst->ServiceNotificationReady(inst->ivars->action);
1837 }
1838 return kIOReturnSuccess;
1839 });
1840 if (interest) {
1841 IOLockLock(inst->ivars->lock);
1842 inst->ivars->interestNotifiers->setObject((const OSSymbol *) newService, interest);
1843 IOLockUnlock(inst->ivars->lock);
1844 }
1845 if (notifyReady) {
1846 if (inst->ivars->action) {
1847 inst->ServiceNotificationReady(inst->ivars->action);
1848 }
1849 }
1850 return false;
1851 });
1852
1853 if (!inst->ivars->notifier) {
1854 OSSafeReleaseNULL(inst);
1855 ret = kIOReturnError;
1856 }
1857
1858 *notification = inst;
1859 ret = kIOReturnSuccess;
1860
1861 return ret;
1862 }
1863
1864 kern_return_t
CopyNextNotification_Impl(uint64_t * type,IOService ** service,uint64_t * options)1865 IOServiceNotificationDispatchSource::CopyNextNotification_Impl(
1866 uint64_t * type,
1867 IOService ** service,
1868 uint64_t * options)
1869 {
1870 IOService * next;
1871 uint32_t idx;
1872
1873 IOLockLock(ivars->lock);
1874 for (idx = 0; idx < kIOServiceNotificationTypeCount; idx++) {
1875 next = (IOService *) ivars->pending[idx]->getObject(0);
1876 if (next) {
1877 next->retain();
1878 ivars->pending[idx]->removeObject(0);
1879 break;
1880 }
1881 }
1882 IOLockUnlock(ivars->lock);
1883
1884 if (idx == kIOServiceNotificationTypeCount) {
1885 idx = kIOServiceNotificationTypeNone;
1886 }
1887 *type = idx;
1888 *service = next;
1889 *options = 0;
1890
1891 return kIOReturnSuccess;
1892 }
1893
1894 bool
init()1895 IOServiceNotificationDispatchSource::init()
1896 {
1897 if (!super::init()) {
1898 return false;
1899 }
1900 ivars = IOMallocType(IOServiceNotificationDispatchSource_IVars);
1901
1902 return true;
1903 }
1904
1905 void
free()1906 IOServiceNotificationDispatchSource::free()
1907 {
1908 if (ivars) {
1909 if (ivars->notifier) {
1910 ivars->notifier->remove();
1911 ivars->notifier = NULL;
1912 }
1913 if (ivars->interestNotifiers) {
1914 OSDictionary * savedInterestNotifiers = NULL;
1915
1916 // the lock is always initialized first, so it should exist
1917 assert(ivars->lock);
1918
1919 // Prevent additional changes to interestNotifiers
1920 IOLockLock(ivars->lock);
1921 savedInterestNotifiers = ivars->interestNotifiers;
1922 ivars->interestNotifiers = NULL;
1923 IOLockUnlock(ivars->lock);
1924
1925 // Remove all interest notifiers
1926 savedInterestNotifiers->iterateObjects(^bool (const OSSymbol * key, OSObject * object) {
1927 IONotifier * interest = (typeof(interest))object;
1928 interest->remove();
1929 return false;
1930 });
1931 OSSafeReleaseNULL(savedInterestNotifiers);
1932 }
1933 for (uint32_t idx = 0; idx < kIOServiceNotificationTypeCount; idx++) {
1934 OSSafeReleaseNULL(ivars->pending[idx]);
1935 }
1936 if (ivars->lock) {
1937 IOLockFree(ivars->lock);
1938 ivars->lock = NULL;
1939 }
1940 OSSafeReleaseNULL(ivars->serverName);
1941 IOFreeType(ivars, IOServiceNotificationDispatchSource_IVars);
1942 }
1943
1944 super::free();
1945 }
1946
1947 kern_return_t
SetHandler_Impl(OSAction * action)1948 IOServiceNotificationDispatchSource::SetHandler_Impl(
1949 OSAction * action)
1950 {
1951 IOReturn ret;
1952 bool notifyReady;
1953
1954 notifyReady = false;
1955
1956 IOLockLock(ivars->lock);
1957 OSSafeReleaseNULL(ivars->action);
1958 action->retain();
1959 ivars->action = action;
1960 if (action) {
1961 for (uint32_t idx = 0; idx < kIOServiceNotificationTypeCount; idx++) {
1962 notifyReady = (ivars->pending[idx]->getCount());
1963 if (notifyReady) {
1964 break;
1965 }
1966 }
1967 }
1968 IOLockUnlock(ivars->lock);
1969
1970 if (notifyReady) {
1971 ServiceNotificationReady(action);
1972 }
1973 ret = kIOReturnSuccess;
1974
1975 return ret;
1976 }
1977
1978 kern_return_t
SetEnableWithCompletion_Impl(bool enable,IODispatchSourceCancelHandler handler)1979 IOServiceNotificationDispatchSource::SetEnableWithCompletion_Impl(
1980 bool enable,
1981 IODispatchSourceCancelHandler handler)
1982 {
1983 if (enable == ivars->enable) {
1984 return kIOReturnSuccess;
1985 }
1986
1987 IOLockLock(ivars->lock);
1988 ivars->enable = enable;
1989 IOLockUnlock(ivars->lock);
1990
1991 return kIOReturnSuccess;
1992 }
1993
1994 kern_return_t
Cancel_Impl(IODispatchSourceCancelHandler handler)1995 IOServiceNotificationDispatchSource::Cancel_Impl(
1996 IODispatchSourceCancelHandler handler)
1997 {
1998 return kIOReturnUnsupported;
1999 }
2000
2001 kern_return_t
CheckForWork_Impl(const IORPC rpc,bool synchronous)2002 IOServiceNotificationDispatchSource::CheckForWork_Impl(
2003 const IORPC rpc,
2004 bool synchronous)
2005 {
2006 return kIOReturnNotReady;
2007 }
2008
2009 kern_return_t
DeliverNotifications(IOServiceNotificationBlock block)2010 IOServiceNotificationDispatchSource::DeliverNotifications(IOServiceNotificationBlock block)
2011 {
2012 return kIOReturnUnsupported;
2013 }
2014
2015
2016 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2017
2018 OSDictionary *
CreatePropertyMatchingDictionary(const char * key,OSObjectPtr value,OSDictionary * matching)2019 IOService::CreatePropertyMatchingDictionary(const char * key, OSObjectPtr value, OSDictionary * matching)
2020 {
2021 OSDictionary * result;
2022 const OSSymbol * keySym;
2023
2024 keySym = OSSymbol::withCString(key);
2025 result = propertyMatching(keySym, (const OSObject *) value, matching);
2026 OSSafeReleaseNULL(keySym);
2027
2028 return result;
2029 }
2030
2031 OSDictionary *
CreatePropertyMatchingDictionary(const char * key,const char * stringValue,OSDictionary * matching)2032 IOService::CreatePropertyMatchingDictionary(const char * key, const char * stringValue, OSDictionary * matching)
2033 {
2034 OSDictionary * result;
2035 OSString * value;
2036
2037 value = OSString::withCString(stringValue);
2038 result = CreatePropertyMatchingDictionary(key, value, matching);
2039 OSSafeReleaseNULL(value);
2040
2041 return result;
2042 }
2043
2044 OSDictionary *
CreateKernelClassMatchingDictionary(OSString * className,OSDictionary * matching)2045 IOService::CreateKernelClassMatchingDictionary(OSString * className, OSDictionary * matching)
2046 {
2047 if (!className) {
2048 return NULL;
2049 }
2050 if (!matching) {
2051 matching = OSDictionary::withCapacity(2);
2052 if (!matching) {
2053 return NULL;
2054 }
2055 }
2056 matching->setObject(kIOProviderClassKey, className);
2057
2058 return matching;
2059 }
2060
2061 OSDictionary *
CreateKernelClassMatchingDictionary(const char * className,OSDictionary * matching)2062 IOService::CreateKernelClassMatchingDictionary(const char * className, OSDictionary * matching)
2063 {
2064 OSDictionary * result;
2065 OSString * string;
2066
2067 string = OSString::withCString(className);
2068 result = CreateKernelClassMatchingDictionary(string, matching);
2069 OSSafeReleaseNULL(string);
2070
2071 return result;
2072 }
2073
2074 OSDictionary *
CreateUserClassMatchingDictionary(OSString * className,OSDictionary * matching)2075 IOService::CreateUserClassMatchingDictionary(OSString * className, OSDictionary * matching)
2076 {
2077 return CreatePropertyMatchingDictionary(kIOUserClassKey, className, matching);
2078 }
2079
2080 OSDictionary *
CreateUserClassMatchingDictionary(const char * className,OSDictionary * matching)2081 IOService::CreateUserClassMatchingDictionary(const char * className, OSDictionary * matching)
2082 {
2083 return CreatePropertyMatchingDictionary(kIOUserClassKey, className, matching);
2084 }
2085
2086 OSDictionary *
CreateNameMatchingDictionary(OSString * serviceName,OSDictionary * matching)2087 IOService::CreateNameMatchingDictionary(OSString * serviceName, OSDictionary * matching)
2088 {
2089 if (!serviceName) {
2090 return NULL;
2091 }
2092 if (!matching) {
2093 matching = OSDictionary::withCapacity(2);
2094 if (!matching) {
2095 return NULL;
2096 }
2097 }
2098 matching->setObject(kIONameMatchKey, serviceName);
2099
2100 return matching;
2101 }
2102
2103 OSDictionary *
CreateNameMatchingDictionary(const char * serviceName,OSDictionary * matching)2104 IOService::CreateNameMatchingDictionary(const char * serviceName, OSDictionary * matching)
2105 {
2106 OSDictionary * result;
2107 OSString * string;
2108
2109 string = OSString::withCString(serviceName);
2110 result = CreateNameMatchingDictionary(string, matching);
2111 OSSafeReleaseNULL(string);
2112
2113 return result;
2114 }
2115
2116
2117
2118 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2119
2120 kern_return_t
waitInterruptTrap(void * p1,void * p2,void * p3,void * p4,void * p5,void * p6)2121 IOUserServer::waitInterruptTrap(void * p1, void * p2, void * p3, void * p4, void * p5, void * p6)
2122 {
2123 IOReturn ret = kIOReturnBadArgument;
2124 IOInterruptState is;
2125 IOInterruptDispatchSource * interrupt;
2126 IOInterruptDispatchSource_IVars * ivars;
2127 IOInterruptDispatchSourcePayload payload;
2128
2129 bool willWait;
2130 bool canceled;
2131 wait_result_t waitResult;
2132 thread_t self;
2133
2134 OSObject * object;
2135
2136 object = iokit_lookup_object_with_port_name((mach_port_name_t)(uintptr_t)p1, IKOT_UEXT_OBJECT, current_task());
2137
2138 if (!object) {
2139 return kIOReturnBadArgument;
2140 }
2141 if (!(interrupt = OSDynamicCast(IOInterruptDispatchSource, object))) {
2142 ret = kIOReturnBadArgument;
2143 } else {
2144 self = current_thread();
2145 ivars = interrupt->ivars;
2146 payload.count = 0;
2147 do {
2148 willWait = false;
2149 is = IOSimpleLockLockDisableInterrupt(ivars->lock);
2150 canceled = ivars->canceled;
2151 if (!canceled) {
2152 if ((payload.count = ivars->count)) {
2153 payload.time = ivars->time;
2154 ivars->count = 0;
2155 waitResult = THREAD_AWAKENED;
2156 } else {
2157 assert(NULL == ivars->waiter);
2158 ivars->waiter = self;
2159 waitResult = assert_wait((event_t) ivars, THREAD_INTERRUPTIBLE);
2160 }
2161 willWait = (waitResult == THREAD_WAITING);
2162 if (willWait && (kIOInterruptTypeLevel & ivars->interruptType) && ivars->enable) {
2163 IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
2164 ivars->provider->enableInterrupt(ivars->intIndex);
2165 } else {
2166 IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
2167 }
2168 } else {
2169 IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
2170 }
2171 if (willWait) {
2172 waitResult = thread_block(THREAD_CONTINUE_NULL);
2173 if (THREAD_INTERRUPTED == waitResult) {
2174 is = IOSimpleLockLockDisableInterrupt(ivars->lock);
2175 ivars->waiter = NULL;
2176 IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
2177 canceled = true;
2178 break;
2179 }
2180 }
2181 } while (!payload.count && !canceled);
2182 ret = (payload.count ? kIOReturnSuccess : kIOReturnAborted);
2183 }
2184
2185 if (kIOReturnSuccess == ret) {
2186 int copyerr = copyout(&payload, (user_addr_t) p2, sizeof(payload));
2187 if (copyerr) {
2188 ret = kIOReturnVMError;
2189 }
2190 }
2191
2192 object->release();
2193
2194 return ret;
2195 }
2196
2197 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2198
2199 kern_return_t
Create_Impl(const char * name,uint64_t tag,uint64_t options,OSString * bundleID,IOUserServer ** server)2200 IOUserServer::Create_Impl(
2201 const char * name,
2202 uint64_t tag,
2203 uint64_t options,
2204 OSString * bundleID,
2205 IOUserServer ** server)
2206 {
2207 IOReturn ret;
2208 IOUserServer * us;
2209 const OSSymbol * sym;
2210 OSNumber * serverTag;
2211 io_name_t rname;
2212 OSKext * kext;
2213
2214 us = (typeof(us))thread_iokit_tls_get(0);
2215 assert(OSDynamicCast(IOUserServer, us));
2216 if (kIODKLogSetup & gIODKDebug) {
2217 DKLOG(DKS "::Create(" DKS ") %p\n", DKN(us), name, tag, us);
2218 }
2219 if (!us) {
2220 return kIOReturnError;
2221 }
2222
2223 if (bundleID) {
2224 kext = OSKext::lookupKextWithIdentifier(bundleID->getCStringNoCopy());
2225 if (kext) {
2226 us->setTaskLoadTag(kext);
2227 us->setDriverKitUUID(kext);
2228 us->setDriverKitStatistics(kext);
2229 OSKext::OSKextLogDriverKitInfoLoad(kext);
2230 OSSafeReleaseNULL(kext);
2231 } else {
2232 DKLOG(DKS "::Create(" DKS "): could not find OSKext for %s\n", DKN(us), name, tag, bundleID->getCStringNoCopy());
2233 }
2234
2235 us->fAllocationName = kern_allocation_name_allocate(bundleID->getCStringNoCopy(), 0);
2236 assert(us->fAllocationName);
2237 }
2238
2239 sym = OSSymbol::withCString(name);
2240 serverTag = OSNumber::withNumber(tag, 64);
2241
2242 us->setProperty(gIOUserServerNameKey, (OSObject *) sym);
2243 us->setProperty(gIOUserServerTagKey, serverTag);
2244
2245 serverTag->release();
2246 OSSafeReleaseNULL(sym);
2247
2248 snprintf(rname, sizeof(rname), "IOUserServer(%s-0x%qx)", name, tag);
2249 us->setName(rname);
2250
2251 us->retain();
2252 *server = us;
2253 ret = kIOReturnSuccess;
2254
2255 return ret;
2256 }
2257
2258 kern_return_t
RegisterService_Impl()2259 IOUserServer::RegisterService_Impl()
2260 {
2261 kern_return_t ret = IOService::RegisterService_Impl();
2262
2263 return ret;
2264 }
2265
2266 kern_return_t
Exit_Impl(const char * reason)2267 IOUserServer::Exit_Impl(
2268 const char * reason)
2269 {
2270 return kIOReturnUnsupported;
2271 }
2272
2273 kern_return_t
LoadModule_Impl(const char * path)2274 IOUserServer::LoadModule_Impl(
2275 const char * path)
2276 {
2277 return kIOReturnUnsupported;
2278 }
2279
2280
2281 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2282
2283 kern_return_t
Create_Impl(const char * name,uint64_t options,uint64_t priority,IODispatchQueue ** queue)2284 IODispatchQueue::Create_Impl(
2285 const char * name,
2286 uint64_t options,
2287 uint64_t priority,
2288 IODispatchQueue ** queue)
2289 {
2290 IODispatchQueue * result;
2291 IOUserServer * us;
2292
2293 result = OSTypeAlloc(IODispatchQueue);
2294 if (!result) {
2295 return kIOReturnNoMemory;
2296 }
2297 if (!result->init()) {
2298 OSSafeReleaseNULL(result);
2299 return kIOReturnNoMemory;
2300 }
2301
2302 *queue = result;
2303
2304 if (!strcmp("Root", name)) {
2305 us = (typeof(us))thread_iokit_tls_get(0);
2306 assert(OSDynamicCast(IOUserServer, us));
2307 us->setRootQueue(result);
2308 }
2309
2310 if (kIODKLogSetup & gIODKDebug) {
2311 DKLOG("IODispatchQueue::Create %s %p\n", name, result);
2312 }
2313
2314 return kIOReturnSuccess;
2315 }
2316
2317 kern_return_t
SetPort_Impl(mach_port_t port)2318 IODispatchQueue::SetPort_Impl(
2319 mach_port_t port)
2320 {
2321 if (MACH_PORT_NULL != ivars->serverPort) {
2322 return kIOReturnNotReady;
2323 }
2324
2325 ivars->serverPort = port;
2326 return kIOReturnSuccess;
2327 }
2328
2329 bool
init()2330 IODispatchQueue::init()
2331 {
2332 ivars = IOMallocType(IODispatchQueue_IVars);
2333 ivars->queue = this;
2334
2335 return true;
2336 }
2337
2338 void
free()2339 IODispatchQueue::free()
2340 {
2341 if (ivars && ivars->serverPort) {
2342 ipc_port_release_send(ivars->serverPort);
2343 ivars->serverPort = MACH_PORT_NULL;
2344 }
2345 IOFreeType(ivars, IODispatchQueue_IVars);
2346 super::free();
2347 }
2348
2349 bool
OnQueue()2350 IODispatchQueue::OnQueue()
2351 {
2352 return false;
2353 }
2354
2355 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2356
2357
2358 kern_return_t
Dispatch(IORPC rpc)2359 OSMetaClassBase::Dispatch(IORPC rpc)
2360 {
2361 return kIOReturnUnsupported;
2362 }
2363
2364 kern_return_t
Invoke(IORPC rpc)2365 OSMetaClassBase::Invoke(IORPC rpc)
2366 {
2367 IOReturn ret = kIOReturnUnsupported;
2368 OSMetaClassBase * object;
2369 OSAction * action;
2370 IOService * service;
2371 IOUserServer * us;
2372 IORPCMessage * message;
2373
2374 assert(rpc.sendSize >= (sizeof(IORPCMessageMach) + sizeof(IORPCMessage)));
2375 message = IORPCMessageFromMach(rpc.message, false);
2376 if (!message) {
2377 return kIOReturnIPCError;
2378 }
2379 message->flags |= kIORPCMessageKernel;
2380
2381 us = NULL;
2382 if (!(kIORPCMessageLocalHost & message->flags)) {
2383 us = OSDynamicCast(IOUserServer, this);
2384 if (!us) {
2385 IOEventLink * eventLink = NULL;
2386 IOWorkGroup * workgroup = NULL;
2387
2388 if ((action = OSDynamicCast(OSAction, this))) {
2389 object = IOUserServer::target(action, message);
2390 } else {
2391 object = this;
2392 }
2393 if ((service = OSDynamicCast(IOService, object))
2394 && service->reserved->uvars) {
2395 // xxx other classes
2396 us = service->reserved->uvars->userServer;
2397 } else if (action) {
2398 us = action->ivars->userServer;
2399 } else if ((eventLink = OSDynamicCast(IOEventLink, object))) {
2400 us = eventLink->ivars->userServer;
2401 } else if ((workgroup = OSDynamicCast(IOWorkGroup, object))) {
2402 us = workgroup->ivars->userServer;
2403 }
2404 }
2405 }
2406 if (us) {
2407 message->flags |= kIORPCMessageRemote;
2408 ret = us->rpc(rpc);
2409 if (kIOReturnSuccess != ret) {
2410 if (kIODKLogIPC & gIODKDebug) {
2411 DKLOG("OSMetaClassBase::Invoke user 0x%x\n", ret);
2412 }
2413 }
2414 } else {
2415 if (kIODKLogIPC & gIODKDebug) {
2416 DKLOG("OSMetaClassBase::Invoke kernel %s 0x%qx\n", getMetaClass()->getClassName(), message->msgid);
2417 }
2418 void * prior = thread_iokit_tls_get(0);
2419 thread_iokit_tls_set(0, NULL);
2420 ret = Dispatch(rpc);
2421 thread_iokit_tls_set(0, prior);
2422 }
2423
2424 return ret;
2425 }
2426
2427 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2428
2429 struct IOPStrings {
2430 uint32_t dataSize;
2431 uint32_t count;
2432 const char strings[0];
2433 };
2434
2435 kern_return_t
Dispatch(IORPC rpc)2436 OSUserMetaClass::Dispatch(IORPC rpc)
2437 {
2438 if (meta) {
2439 return const_cast<OSMetaClass *>(meta)->Dispatch(rpc);
2440 } else {
2441 return kIOReturnUnsupported;
2442 }
2443 }
2444
2445 void
free()2446 OSUserMetaClass::free()
2447 {
2448 if (queueNames) {
2449 IOFreeData(queueNames, sizeof(IOPStrings) + queueNames->dataSize * sizeof(char));
2450 queueNames = NULL;
2451 }
2452 if (description) {
2453 IOFreeData(description, description->descriptionSize);
2454 description = NULL;
2455 }
2456 IODeleteData(methods, uint64_t, 2 * methodCount);
2457 if (meta) {
2458 meta->releaseMetaClass();
2459 }
2460 if (name) {
2461 name->release();
2462 }
2463 OSObject::free();
2464 }
2465
2466 /*
2467 * Sets the loadTag of the associated OSKext
2468 * in the dext task.
2469 * NOTE: different instances of the same OSKext
2470 * (so same BounleID but different tasks)
2471 * will have the same loadTag.
2472 */
2473 void
setTaskLoadTag(OSKext * kext)2474 IOUserServer::setTaskLoadTag(OSKext *kext)
2475 {
2476 task_t owningTask;
2477 uint32_t loadTag, prev_taskloadTag;
2478
2479 owningTask = this->fOwningTask;
2480 if (!owningTask) {
2481 printf("%s: fOwningTask not found\n", __FUNCTION__);
2482 return;
2483 }
2484
2485 loadTag = kext->getLoadTag();
2486 prev_taskloadTag = set_task_loadTag(owningTask, loadTag);
2487 if (prev_taskloadTag) {
2488 printf("%s: found the task loadTag already set to %u (set to %u)\n",
2489 __FUNCTION__, prev_taskloadTag, loadTag);
2490 }
2491 }
2492
2493 /*
2494 * Sets the OSKext uuid as the uuid of the userspace
2495 * dext executable.
2496 */
2497 void
setDriverKitUUID(OSKext * kext)2498 IOUserServer::setDriverKitUUID(OSKext *kext)
2499 {
2500 task_t task;
2501 proc_t p;
2502 uuid_t p_uuid, k_uuid;
2503 OSData *k_data_uuid;
2504 OSData *new_uuid;
2505 uuid_string_t uuid_string = "";
2506
2507 task = this->fOwningTask;
2508 if (!task) {
2509 printf("%s: fOwningTask not found\n", __FUNCTION__);
2510 return;
2511 }
2512
2513 p = (proc_t)(get_bsdtask_info(task));
2514 if (!p) {
2515 printf("%s: proc not found\n", __FUNCTION__);
2516 return;
2517 }
2518 proc_getexecutableuuid(p, p_uuid, sizeof(p_uuid));
2519
2520 k_data_uuid = kext->copyUUID();
2521 if (k_data_uuid) {
2522 memcpy(&k_uuid, k_data_uuid->getBytesNoCopy(), sizeof(k_uuid));
2523 OSSafeReleaseNULL(k_data_uuid);
2524 if (uuid_compare(k_uuid, p_uuid) != 0) {
2525 printf("%s: uuid not matching\n", __FUNCTION__);
2526 }
2527 return;
2528 }
2529
2530 uuid_unparse(p_uuid, uuid_string);
2531 new_uuid = OSData::withValue(p_uuid);
2532 kext->setDriverKitUUID(new_uuid);
2533 }
2534
2535 void
setDriverKitStatistics(OSKext * kext)2536 IOUserServer::setDriverKitStatistics(OSKext *kext)
2537 {
2538 OSDextStatistics * statistics = kext->copyDextStatistics();
2539 if (statistics == NULL) {
2540 panic("Kext %s was not a DriverKit OSKext", kext->getIdentifierCString());
2541 }
2542 fStatistics = statistics;
2543 }
2544
2545 void
setCheckInToken(IOUserServerCheckInToken * token)2546 IOUserServer::setCheckInToken(IOUserServerCheckInToken *token)
2547 {
2548 if (token != NULL && fCheckInToken == NULL) {
2549 token->retain();
2550 fCheckInToken = token;
2551 iokit_clear_registered_ports(fOwningTask);
2552 } else {
2553 printf("%s: failed to set check in token. token=%p, fCheckInToken=%p\n", __FUNCTION__, token, fCheckInToken);
2554 }
2555 }
2556
2557 bool
serviceMatchesCheckInToken(IOUserServerCheckInToken * token)2558 IOUserServer::serviceMatchesCheckInToken(IOUserServerCheckInToken *token)
2559 {
2560 if (token != NULL) {
2561 bool result = token == fCheckInToken;
2562 if (result) {
2563 fCheckInToken->complete();
2564 }
2565 return result;
2566 } else {
2567 printf("%s: null check in token\n", __FUNCTION__);
2568 return false;
2569 }
2570 }
2571
2572 // entitlements - dict of entitlements to check
2573 // prop - string - if present return true
2574 // - array of strings - if any present return true
2575 // - array of arrays of strings - in each leaf array all must be present
2576 // - if any top level array succeeds return true
2577 // consumes one reference of prop
2578 bool
checkEntitlements(OSDictionary * entitlements,OSObject * prop,IOService * provider,IOService * dext)2579 IOUserServer::checkEntitlements(
2580 OSDictionary * entitlements, OSObject * prop,
2581 IOService * provider, IOService * dext)
2582 {
2583 OSDictionary * matching;
2584
2585 if (!prop) {
2586 return true;
2587 }
2588 if (!entitlements) {
2589 OSSafeReleaseNULL(prop);
2590 return false;
2591 }
2592
2593 matching = NULL;
2594 if (dext) {
2595 matching = dext->dictionaryWithProperties();
2596 if (!matching) {
2597 OSSafeReleaseNULL(prop);
2598 return false;
2599 }
2600 }
2601
2602 bool allPresent __block;
2603 prop->iterateObjects(^bool (OSObject * object) {
2604 allPresent = false;
2605 object->iterateObjects(^bool (OSObject * object) {
2606 OSString * string;
2607 OSObject * value;
2608 string = OSDynamicCast(OSString, object);
2609 value = entitlements->getObject(string);
2610 if (matching && value) {
2611 matching->setObject(string, value);
2612 }
2613 allPresent = (NULL != value);
2614 // early terminate if not found
2615 return !allPresent;
2616 });
2617 // early terminate if found
2618 return allPresent;
2619 });
2620
2621 if (allPresent && matching && provider) {
2622 allPresent = provider->matchPropertyTable(matching);
2623 }
2624
2625 OSSafeReleaseNULL(matching);
2626 OSSafeReleaseNULL(prop);
2627
2628 return allPresent;
2629 }
2630
2631 bool
checkEntitlements(IOService * provider,IOService * dext)2632 IOUserServer::checkEntitlements(IOService * provider, IOService * dext)
2633 {
2634 OSObject * prop;
2635 bool ok;
2636
2637 if (!fOwningTask) {
2638 return false;
2639 }
2640
2641 prop = provider->copyProperty(gIOServiceDEXTEntitlementsKey);
2642 ok = checkEntitlements(fEntitlements, prop, provider, dext);
2643 if (!ok) {
2644 DKLOG(DKS ": provider entitlements check failed\n", DKN(dext));
2645 }
2646 if (ok) {
2647 prop = dext->copyProperty(gIOServiceDEXTEntitlementsKey);
2648 ok = checkEntitlements(fEntitlements, prop, NULL, NULL);
2649 if (!ok) {
2650 DKLOG(DKS ": family entitlements check failed\n", DKN(dext));
2651 }
2652 }
2653
2654 return ok;
2655 }
2656
2657 IOReturn
exit(const char * reason)2658 IOUserServer::exit(const char * reason)
2659 {
2660 DKLOG("%s::exit(%s)\n", getName(), reason);
2661 Exit(reason);
2662 return kIOReturnSuccess;
2663 }
2664
2665 IOReturn
kill(const char * reason)2666 IOUserServer::kill(const char * reason)
2667 {
2668 IOReturn ret = kIOReturnError;
2669 if (fOwningTask != NULL) {
2670 DKLOG("%s::kill(%s)\n", getName(), reason);
2671 task_bsdtask_kill(fOwningTask);
2672 ret = kIOReturnSuccess;
2673 }
2674 return ret;
2675 }
2676
2677 OSObjectUserVars *
varsForObject(OSObject * obj)2678 IOUserServer::varsForObject(OSObject * obj)
2679 {
2680 IOService * service;
2681
2682 if ((service = OSDynamicCast(IOService, obj))) {
2683 return service->reserved->uvars;
2684 }
2685
2686 return NULL;
2687 }
2688
2689 IOPStrings *
copyInStringArray(const char * string,uint32_t userSize)2690 IOUserServer::copyInStringArray(const char * string, uint32_t userSize)
2691 {
2692 IOPStrings * array;
2693 vm_size_t alloc;
2694 size_t len;
2695 const char * end;
2696 OSBoundedPtr<const char> cstr;
2697
2698 if (userSize <= 1) {
2699 return NULL;
2700 }
2701
2702 if (os_add_overflow(sizeof(IOPStrings), userSize, &alloc)) {
2703 assert(false);
2704 return NULL;
2705 }
2706 if (alloc > 16384) {
2707 assert(false);
2708 return NULL;
2709 }
2710 array = (typeof(array))IOMallocData(alloc);
2711 if (!array) {
2712 return NULL;
2713 }
2714 array->dataSize = userSize;
2715 bcopy(string, (void *) &array->strings[0], userSize);
2716
2717 array->count = 0;
2718 end = &array->strings[array->dataSize];
2719 cstr = OSBoundedPtr<const char>(&array->strings[0], &array->strings[0], end);
2720 while ((len = (unsigned char)cstr[0])) {
2721 cstr++;
2722 if ((cstr + len) >= end) {
2723 break;
2724 }
2725 cstr += len;
2726 array->count++;
2727 }
2728 if (len) {
2729 IOFreeData(array, alloc);
2730 array = NULL;
2731 }
2732
2733 return array;
2734 }
2735
2736 uint32_t
stringArrayIndex(IOPStrings * array,const char * look)2737 IOUserServer::stringArrayIndex(IOPStrings * array, const char * look)
2738 {
2739 uint32_t idx;
2740 size_t len, llen;
2741 OSBoundedPtr<const char> cstr;
2742 const char * end;
2743
2744 idx = 0;
2745 end = &array->strings[array->dataSize];
2746 cstr = OSBoundedPtr<const char>(&array->strings[0], &array->strings[0], end);
2747
2748 llen = strlen(look);
2749 while ((len = (unsigned char)cstr[0])) {
2750 cstr++;
2751 if ((cstr + len) >= end) {
2752 break;
2753 }
2754 if ((len == llen) && !strncmp(cstr.discard_bounds(), look, len)) {
2755 return idx;
2756 }
2757 cstr += len;
2758 idx++;
2759 }
2760
2761 return -1U;
2762 }
2763 #define kIODispatchQueueStopped ((IODispatchQueue *) -1L)
2764
2765 IODispatchQueue *
queueForObject(OSObject * obj,uint64_t msgid)2766 IOUserServer::queueForObject(OSObject * obj, uint64_t msgid)
2767 {
2768 IODispatchQueue * queue;
2769 OSObjectUserVars * uvars;
2770 uint64_t option;
2771
2772 uvars = varsForObject(obj);
2773 if (!uvars) {
2774 return NULL;
2775 }
2776 if (!uvars->queueArray) {
2777 if (uvars->stopped) {
2778 return kIODispatchQueueStopped;
2779 }
2780 return NULL;
2781 }
2782 queue = uvars->queueArray[0];
2783
2784 if (uvars->userMeta
2785 && uvars->userMeta->methods) {
2786 uint32_t idx, baseIdx;
2787 uint32_t lim;
2788 // bsearch
2789 for (baseIdx = 0, lim = uvars->userMeta->methodCount; lim; lim >>= 1) {
2790 idx = baseIdx + (lim >> 1);
2791 if (msgid == uvars->userMeta->methods[idx]) {
2792 option = uvars->userMeta->methods[uvars->userMeta->methodCount + idx];
2793 option &= 0xFF;
2794 if (option < uvars->userMeta->queueNames->count) {
2795 queue = uvars->queueArray[option + 1];
2796 }
2797 break;
2798 } else if (msgid > uvars->userMeta->methods[idx]) {
2799 // move right
2800 baseIdx += (lim >> 1) + 1;
2801 lim--;
2802 }
2803 // else move left
2804 }
2805 }
2806 return queue;
2807 }
2808
2809 IOReturn
objectInstantiate(OSObject * obj,IORPC rpc,IORPCMessage * message)2810 IOUserServer::objectInstantiate(OSObject * obj, IORPC rpc, IORPCMessage * message)
2811 {
2812 IOReturn ret;
2813 OSString * str;
2814 OSObject * prop;
2815 IOService * service;
2816
2817 OSAction * action;
2818 OSObject * target;
2819 uint32_t queueCount, queueAlloc;
2820 const char * resultClassName;
2821 uint64_t resultFlags;
2822
2823 mach_msg_size_t replySize;
2824 uint32_t methodCount;
2825 const uint64_t * methods;
2826 IODispatchQueue * queue;
2827 OSUserMetaClass * userMeta;
2828 OSObjectUserVars * uvars;
2829 uint32_t idx;
2830 ipc_port_t sendPort;
2831
2832 OSObject_Instantiate_Rpl_Content * reply;
2833 IODispatchQueue ** unboundedQueueArray = NULL;
2834 queueCount = 0;
2835 methodCount = 0;
2836 methods = NULL;
2837 str = NULL;
2838 prop = NULL;
2839 userMeta = NULL;
2840 resultClassName = NULL;
2841 resultFlags = 0;
2842 ret = kIOReturnUnsupportedMode;
2843
2844 service = OSDynamicCast(IOService, obj);
2845 action = OSDynamicCast(OSAction, obj);
2846 if (!service) {
2847 // xxx other classes hosted
2848 resultFlags |= kOSObjectRPCKernel;
2849 resultFlags |= kOSObjectRPCRemote;
2850 } else {
2851 if (service->isInactive()) {
2852 DKLOG(DKS "::instantiate inactive\n", DKN(service));
2853 return kIOReturnOffline;
2854 }
2855 prop = service->copyProperty(gIOUserClassKey);
2856 str = OSDynamicCast(OSString, prop);
2857 if (!service->reserved->uvars) {
2858 resultFlags |= kOSObjectRPCRemote;
2859 resultFlags |= kOSObjectRPCKernel;
2860 } else if (this != service->reserved->uvars->userServer) {
2861 // remote, use base class
2862 resultFlags |= kOSObjectRPCRemote;
2863 }
2864 if (service->reserved->uvars && service->reserved->uvars->userServer) {
2865 if (!str) {
2866 DKLOG("no IOUserClass defined for " DKS "\n", DKN(service));
2867 OSSafeReleaseNULL(prop);
2868 return kIOReturnError;
2869 }
2870 IOLockLock(service->reserved->uvars->userServer->fLock);
2871 userMeta = (typeof(userMeta))service->reserved->uvars->userServer->fClasses->getObject(str);
2872 IOLockUnlock(service->reserved->uvars->userServer->fLock);
2873 }
2874 }
2875 if (!str && !userMeta) {
2876 const OSMetaClass * meta;
2877 meta = obj->getMetaClass();
2878 IOLockLock(fLock);
2879 if (action) {
2880 str = action->ivars->typeName;
2881 if (str) {
2882 userMeta = (typeof(userMeta))fClasses->getObject(str);
2883 }
2884 }
2885 while (meta && !userMeta) {
2886 str = (OSString *) meta->getClassNameSymbol();
2887 userMeta = (typeof(userMeta))fClasses->getObject(str);
2888 if (!userMeta) {
2889 meta = meta->getSuperClass();
2890 }
2891 }
2892 IOLockUnlock(fLock);
2893 }
2894 if (str) {
2895 if (!userMeta) {
2896 IOLockLock(fLock);
2897 userMeta = (typeof(userMeta))fClasses->getObject(str);
2898 IOLockUnlock(fLock);
2899 }
2900 if (kIODKLogSetup & gIODKDebug) {
2901 DKLOG("userMeta %s %p\n", str->getCStringNoCopy(), userMeta);
2902 }
2903 if (userMeta) {
2904 if (kOSObjectRPCRemote & resultFlags) {
2905 if (!action) {
2906 /* Special case: For OSAction subclasses, do not use the superclass */
2907 while (userMeta && !(kOSClassCanRemote & userMeta->description->flags)) {
2908 userMeta = userMeta->superMeta;
2909 }
2910 }
2911 if (userMeta) {
2912 resultClassName = userMeta->description->name;
2913 ret = kIOReturnSuccess;
2914 }
2915 } else {
2916 service->reserved->uvars->userMeta = userMeta;
2917 queueAlloc = 1;
2918 if (userMeta->queueNames) {
2919 queueAlloc += userMeta->queueNames->count;
2920 }
2921 unboundedQueueArray = IONewZero(IODispatchQueue *, queueAlloc);
2922 service->reserved->uvars->queueArray =
2923 OSBoundedArrayRef<IODispatchQueue *>(unboundedQueueArray, queueAlloc);
2924 resultClassName = str->getCStringNoCopy();
2925 ret = kIOReturnSuccess;
2926 }
2927 } else if (kIODKLogSetup & gIODKDebug) {
2928 DKLOG("userMeta %s was not found in fClasses\n", str->getCStringNoCopy());
2929 IOLockLock(fLock);
2930 fClasses->iterateObjects(^bool (const OSSymbol * key, OSObject * val) {
2931 DKLOG(" fClasses[\"%s\"] => %p\n", key->getCStringNoCopy(), val);
2932 return false;
2933 });
2934 IOLockUnlock(fLock);
2935 }
2936 }
2937 OSSafeReleaseNULL(prop);
2938
2939 IORPCMessageMach * machReply = rpc.reply;
2940 replySize = sizeof(OSObject_Instantiate_Rpl);
2941
2942 if ((kIOReturnSuccess == ret) && (kOSObjectRPCRemote & resultFlags)) {
2943 target = obj;
2944 if (action) {
2945 if (action->ivars->referenceSize) {
2946 resultFlags |= kOSObjectRPCKernel;
2947 } else {
2948 resultFlags &= ~kOSObjectRPCKernel;
2949 if (action->ivars->target) {
2950 target = action->ivars->target;
2951 queueCount = 1;
2952 queue = queueForObject(target, action->ivars->targetmsgid);
2953 if (!queue && action->ivars->userServer) {
2954 queue = action->ivars->userServer->fRootQueue;
2955 }
2956 idx = 0;
2957 sendPort = NULL;
2958 if (queue && (kIODispatchQueueStopped != queue)) {
2959 sendPort = ipc_port_copy_send_mqueue(queue->ivars->serverPort);
2960 }
2961 replySize = sizeof(OSObject_Instantiate_Rpl)
2962 + queueCount * sizeof(machReply->objects[0])
2963 + 2 * methodCount * sizeof(reply->methods[0]);
2964 if (replySize > rpc.replySize) {
2965 assert(false);
2966 return kIOReturnIPCError;
2967 }
2968 machReply->objects[idx].type = MACH_MSG_PORT_DESCRIPTOR;
2969 machReply->objects[idx].disposition = MACH_MSG_TYPE_MOVE_SEND;
2970 machReply->objects[idx].name = sendPort;
2971 machReply->objects[idx].pad2 = 0;
2972 machReply->objects[idx].pad_end = 0;
2973 }
2974 }
2975 } else {
2976 uvars = varsForObject(target);
2977 if (uvars && uvars->userMeta) {
2978 queueCount = 1;
2979 if (uvars->userMeta->queueNames) {
2980 queueCount += uvars->userMeta->queueNames->count;
2981 }
2982 methods = &uvars->userMeta->methods[0];
2983 methodCount = uvars->userMeta->methodCount;
2984 replySize = sizeof(OSObject_Instantiate_Rpl)
2985 + queueCount * sizeof(machReply->objects[0])
2986 + 2 * methodCount * sizeof(reply->methods[0]);
2987 if (replySize > rpc.replySize) {
2988 assert(false);
2989 return kIOReturnIPCError;
2990 }
2991 for (idx = 0; idx < queueCount; idx++) {
2992 queue = uvars->queueArray[idx];
2993 sendPort = NULL;
2994 if (queue) {
2995 sendPort = ipc_port_copy_send_mqueue(queue->ivars->serverPort);
2996 }
2997 machReply->objects[idx].type = MACH_MSG_PORT_DESCRIPTOR;
2998 machReply->objects[idx].disposition = MACH_MSG_TYPE_MOVE_SEND;
2999 machReply->objects[idx].name = sendPort;
3000 machReply->objects[idx].pad2 = 0;
3001 machReply->objects[idx].pad_end = 0;
3002 }
3003 }
3004 }
3005 }
3006
3007 if (kIODKLogIPC & gIODKDebug) {
3008 DKLOG("instantiate object %s with user class %s\n", obj->getMetaClass()->getClassName(), str ? str->getCStringNoCopy() : "(null)");
3009 }
3010
3011 if (kIOReturnSuccess != ret) {
3012 DKLOG("%s: no user class found\n", str ? str->getCStringNoCopy() : obj->getMetaClass()->getClassName());
3013 resultClassName = "unknown";
3014 }
3015
3016 machReply->msgh.msgh_id = kIORPCVersionCurrentReply;
3017 machReply->msgh.msgh_size = replySize;
3018 machReply->msgh_body.msgh_descriptor_count = queueCount;
3019
3020 reply = (typeof(reply))IORPCMessageFromMach(machReply, true);
3021 if (!reply) {
3022 return kIOReturnIPCError;
3023 }
3024 if (methodCount) {
3025 bcopy(methods, &reply->methods[0], methodCount * 2 * sizeof(reply->methods[0]));
3026 }
3027 reply->__hdr.msgid = OSObject_Instantiate_ID;
3028 reply->__hdr.flags = kIORPCMessageOneway;
3029 reply->__hdr.objectRefs = 0;
3030 reply->__pad = 0;
3031 reply->flags = resultFlags;
3032 strlcpy(reply->classname, resultClassName, sizeof(reply->classname));
3033 reply->__result = ret;
3034
3035 ret = kIOReturnSuccess;
3036
3037 return ret;
3038 }
3039
3040 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3041
3042 IOReturn
kernelDispatch(OSObject * obj,IORPC rpc)3043 IOUserServer::kernelDispatch(OSObject * obj, IORPC rpc)
3044 {
3045 IOReturn ret;
3046 IORPCMessage * message;
3047
3048 message = IORPCMessageFromMach(rpc.message, false);
3049 if (!message) {
3050 return kIOReturnIPCError;
3051 }
3052
3053 if (OSObject_Instantiate_ID == message->msgid) {
3054 ret = objectInstantiate(obj, rpc, message);
3055 if (kIOReturnSuccess != ret) {
3056 DKLOG("%s: instantiate failed 0x%x\n", obj->getMetaClass()->getClassName(), ret);
3057 }
3058 } else {
3059 if (kIODKLogIPC & gIODKDebug) {
3060 DKLOG("%s::Dispatch kernel 0x%qx\n", obj->getMetaClass()->getClassName(), message->msgid);
3061 }
3062 ret = obj->Dispatch(rpc);
3063 if (kIODKLogIPC & gIODKDebug) {
3064 DKLOG("%s::Dispatch kernel 0x%qx result 0x%x\n", obj->getMetaClass()->getClassName(), message->msgid, ret);
3065 }
3066 }
3067
3068 return ret;
3069 }
3070
3071
3072 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3073
3074 OSObject *
target(OSAction * action,IORPCMessage * message)3075 IOUserServer::target(OSAction * action, IORPCMessage * message)
3076 {
3077 OSObject * object;
3078
3079 if (message->msgid != action->ivars->msgid) {
3080 return action;
3081 }
3082 object = action->ivars->target;
3083 if (!object) {
3084 return action;
3085 }
3086 message->msgid = action->ivars->targetmsgid;
3087 message->objects[0] = (OSObjectRef) object;
3088 if (kIORPCMessageRemote & message->flags) {
3089 object->retain();
3090 #ifndef __clang_analyzer__
3091 // Hide the release of 'action' from the clang static analyzer to suppress
3092 // an overrelease diagnostic. The analyzer doesn't have a way to express the
3093 // non-standard contract of this method, which is that it releases 'action' when
3094 // the message flags have kIORPCMessageRemote set.
3095 action->release();
3096 #endif
3097 }
3098 if (kIODKLogIPC & gIODKDebug) {
3099 DKLOG("TARGET %s msg 0x%qx from 0x%qx\n", object->getMetaClass()->getClassName(), message->msgid, action->ivars->msgid);
3100 }
3101
3102 return object;
3103 }
3104
3105 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3106
3107 kern_return_t
uext_server(ipc_port_t receiver,ipc_kmsg_t requestkmsg,ipc_kmsg_t * pReply)3108 uext_server(ipc_port_t receiver, ipc_kmsg_t requestkmsg, ipc_kmsg_t * pReply)
3109 {
3110 kern_return_t ret;
3111 OSObject * object;
3112 IOUserServer * server;
3113
3114 object = IOUserServer::copyObjectForSendRight(receiver, IKOT_UEXT_OBJECT);
3115 server = OSDynamicCast(IOUserServer, object);
3116 if (!server) {
3117 OSSafeReleaseNULL(object);
3118 return KERN_INVALID_NAME;
3119 }
3120 ret = server->server(requestkmsg, pReply);
3121 object->release();
3122
3123 return ret;
3124 }
3125
3126 /*
3127 * Chosen to hit kalloc zones (as opposed to the VM).
3128 * doesn't include the trailer size which ipc_kmsg_alloc() will add
3129 */
3130 #define MAX_UEXT_REPLY_SIZE 0x17c0
3131 static_assert(MAX_UEXT_REPLY_SIZE + MAX_TRAILER_SIZE <= KALLOC_SAFE_ALLOC_SIZE);
3132
3133 kern_return_t
server(ipc_kmsg_t requestkmsg,ipc_kmsg_t * pReply)3134 IOUserServer::server(ipc_kmsg_t requestkmsg, ipc_kmsg_t * pReply)
3135 {
3136 kern_return_t ret;
3137 mach_msg_size_t replyAlloc;
3138 ipc_kmsg_t replykmsg;
3139 IORPCMessageMach * msgin;
3140 IORPCMessage * message;
3141 IORPCMessageMach * msgout;
3142 IORPCMessage * reply;
3143 uint32_t replySize;
3144 OSObject * object;
3145 OSAction * action;
3146 bool oneway;
3147 uint64_t msgid;
3148
3149 msgin = (typeof(msgin))ikm_header(requestkmsg);
3150 replyAlloc = 0;
3151 msgout = NULL;
3152 replykmsg = NULL;
3153
3154 if (msgin->msgh.msgh_size < (sizeof(IORPCMessageMach) + sizeof(IORPCMessage))) {
3155 if (kIODKLogIPC & gIODKDebug) {
3156 DKLOG("UEXT notify %o\n", msgin->msgh.msgh_id);
3157 }
3158 return KERN_NOT_SUPPORTED;
3159 }
3160
3161 if (!(MACH_MSGH_BITS_COMPLEX & msgin->msgh.msgh_bits)) {
3162 msgin->msgh_body.msgh_descriptor_count = 0;
3163 }
3164 message = IORPCMessageFromMach(msgin, false);
3165 if (!message) {
3166 return kIOReturnIPCError;
3167 }
3168 if (message->objectRefs == 0) {
3169 return kIOReturnIPCError;
3170 }
3171 ret = copyInObjects(msgin, message, msgin->msgh.msgh_size, true, false);
3172 if (kIOReturnSuccess != ret) {
3173 if (kIODKLogIPC & gIODKDebug) {
3174 DKLOG("UEXT copyin(0x%x) %x\n", ret, msgin->msgh.msgh_id);
3175 }
3176 return KERN_NOT_SUPPORTED;
3177 }
3178
3179 if (msgin->msgh_body.msgh_descriptor_count < 1) {
3180 return KERN_NOT_SUPPORTED;
3181 }
3182 object = (OSObject *) message->objects[0];
3183 msgid = message->msgid;
3184 message->flags &= ~kIORPCMessageKernel;
3185 message->flags |= kIORPCMessageRemote;
3186
3187 if ((action = OSDynamicCast(OSAction, object))) {
3188 object = target(action, message);
3189 msgid = message->msgid;
3190 }
3191
3192 oneway = (0 != (kIORPCMessageOneway & message->flags));
3193 assert(oneway || (MACH_PORT_NULL != msgin->msgh.msgh_local_port));
3194
3195 replyAlloc = oneway ? 0 : MAX_UEXT_REPLY_SIZE;
3196 if (replyAlloc) {
3197 /*
3198 * Same as:
3199 * ipc_kmsg_alloc(replyAlloc, 0,
3200 * IPC_KMSG_ALLOC_KERNEL | IPC_KMSG_ALLOC_ZERO | IPC_KMSG_ALLOC_LINEAR |
3201 * IPC_KMSG_ALLOC_NOFAIL);
3202 */
3203 replykmsg = ipc_kmsg_alloc_uext_reply(replyAlloc);
3204 msgout = (typeof(msgout))ikm_header(replykmsg);
3205 }
3206
3207 IORPC rpc = { .message = msgin, .reply = msgout, .sendSize = msgin->msgh.msgh_size, .replySize = replyAlloc };
3208
3209 if (object) {
3210 kern_allocation_name_t prior;
3211 bool setAllocationName;
3212
3213 setAllocationName = (NULL != fAllocationName);
3214 if (setAllocationName) {
3215 prior = thread_set_allocation_name(fAllocationName);
3216 }
3217 thread_iokit_tls_set(0, this);
3218 ret = kernelDispatch(object, rpc);
3219 thread_iokit_tls_set(0, NULL);
3220 if (setAllocationName) {
3221 thread_set_allocation_name(prior);
3222 }
3223 } else {
3224 ret = kIOReturnBadArgument;
3225 }
3226
3227 // release objects
3228 consumeObjects(message, msgin->msgh.msgh_size);
3229
3230 // release ports
3231 copyInObjects(msgin, message, msgin->msgh.msgh_size, false, true);
3232
3233 if (!oneway) {
3234 if (kIOReturnSuccess == ret) {
3235 replySize = msgout->msgh.msgh_size;
3236 reply = IORPCMessageFromMach(msgout, true);
3237 if (!reply) {
3238 ret = kIOReturnIPCError;
3239 } else {
3240 ret = copyOutObjects(msgout, reply, replySize, (kIORPCVersionCurrentReply == msgout->msgh.msgh_id) /* =>!InvokeReply */);
3241 }
3242 }
3243 if (kIOReturnSuccess != ret) {
3244 IORPCMessageErrorReturnContent * errorMsg;
3245
3246 msgout->msgh_body.msgh_descriptor_count = 0;
3247 msgout->msgh.msgh_id = kIORPCVersionCurrentReply;
3248 errorMsg = (typeof(errorMsg))IORPCMessageFromMach(msgout, true);
3249 errorMsg->hdr.msgid = message->msgid;
3250 errorMsg->hdr.flags = kIORPCMessageOneway | kIORPCMessageError;
3251 errorMsg->hdr.objectRefs = 0;
3252 errorMsg->result = ret;
3253 errorMsg->pad = 0;
3254 replySize = sizeof(IORPCMessageErrorReturn);
3255 }
3256
3257 msgout->msgh.msgh_bits = MACH_MSGH_BITS_COMPLEX |
3258 MACH_MSGH_BITS_SET(MACH_MSGH_BITS_LOCAL(msgin->msgh.msgh_bits) /*remote*/, 0 /*local*/, 0, 0);
3259
3260 msgout->msgh.msgh_remote_port = msgin->msgh.msgh_local_port;
3261 msgout->msgh.msgh_local_port = MACH_PORT_NULL;
3262 msgout->msgh.msgh_voucher_port = (mach_port_name_t) 0;
3263 msgout->msgh.msgh_reserved = 0;
3264 msgout->msgh.msgh_size = replySize;
3265 }
3266
3267 *pReply = replykmsg;
3268 return KERN_SUCCESS;
3269 }
3270
3271 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3272
3273 #define MAX_OBJECT_COUNT(mach, size, message) \
3274 ((uint32_t)(((((size) + ((uintptr_t) (mach))) - ((uintptr_t) (&message->objects[0]))) / sizeof(OSObjectRef))))
3275
3276 #pragma pack(push, 4)
3277 struct UEXTTrapReply {
3278 uint64_t replySize;
3279 IORPCMessage replyMessage;
3280 };
3281 #pragma pack(pop)
3282
3283 kern_return_t
IOUserServerUEXTTrap(OSObject * object,void * p1,void * p2,void * p3,void * p4,void * p5,void * p6)3284 IOUserServerUEXTTrap(OSObject * object, void * p1, void * p2, void * p3, void * p4, void * p5, void * p6)
3285 {
3286 const user_addr_t msg = (uintptr_t) p1;
3287 size_t inSize = (uintptr_t) p2;
3288 user_addr_t out = (uintptr_t) p3;
3289 size_t outSize = (uintptr_t) p4;
3290 mach_port_name_t objectName1 = (mach_port_name_t)(uintptr_t) p5;
3291 size_t totalSize;
3292 OSObject * objectArg1;
3293
3294 IORPCMessageMach * mach;
3295 mach_msg_port_descriptor_t * descs;
3296
3297 #pragma pack(4)
3298 struct {
3299 uint32_t pad;
3300 IORPCMessageMach mach;
3301 mach_msg_port_descriptor_t objects[2];
3302 IOTrapMessageBuffer buffer;
3303 } buffer;
3304 #pragma pack()
3305
3306 IOReturn ret;
3307 OSAction * action;
3308 int copyerr;
3309 IORPCMessage * message;
3310 IORPCMessage * reply;
3311 IORPC rpc;
3312 uint64_t refs;
3313 uint32_t maxObjectCount;
3314 size_t copySize;
3315 UEXTTrapReply * replyHdr;
3316 uintptr_t p;
3317
3318 bzero(&buffer, sizeof(buffer));
3319
3320 p = (typeof(p)) & buffer.buffer[0];
3321 if (os_add_overflow(inSize, outSize, &totalSize)) {
3322 return kIOReturnMessageTooLarge;
3323 }
3324 if (totalSize > sizeof(buffer.buffer)) {
3325 return kIOReturnMessageTooLarge;
3326 }
3327 if (inSize < sizeof(IORPCMessage)) {
3328 return kIOReturnIPCError;
3329 }
3330 copyerr = copyin(msg, &buffer.buffer[0], inSize);
3331 if (copyerr) {
3332 return kIOReturnVMError;
3333 }
3334
3335 message = (typeof(message))p;
3336 refs = message->objectRefs;
3337 if ((refs > 2) || !refs) {
3338 return kIOReturnUnsupported;
3339 }
3340 if (!(kIORPCMessageSimpleReply & message->flags)) {
3341 return kIOReturnUnsupported;
3342 }
3343 message->flags &= ~(kIORPCMessageKernel | kIORPCMessageRemote);
3344
3345 descs = (typeof(descs))(p - refs * sizeof(*descs));
3346 mach = (typeof(mach))(p - refs * sizeof(*descs) - sizeof(*mach));
3347
3348 mach->msgh.msgh_id = kIORPCVersionCurrent;
3349 mach->msgh.msgh_size = (mach_msg_size_t) (sizeof(IORPCMessageMach) + refs * sizeof(*descs) + inSize); // totalSize was checked
3350 mach->msgh_body.msgh_descriptor_count = ((mach_msg_size_t) refs);
3351
3352 rpc.message = mach;
3353 rpc.sendSize = mach->msgh.msgh_size;
3354 rpc.reply = (IORPCMessageMach *) (p + inSize);
3355 rpc.replySize = ((uint32_t) (sizeof(buffer.buffer) - inSize)); // inSize was checked
3356
3357 message->objects[0] = 0;
3358 if ((action = OSDynamicCast(OSAction, object))) {
3359 maxObjectCount = MAX_OBJECT_COUNT(rpc.message, rpc.sendSize, message);
3360 if (refs > maxObjectCount) {
3361 return kIOReturnBadArgument;
3362 }
3363 if (refs < 2) {
3364 DKLOG("invalid refs count %qd in message id 0x%qx\n", refs, message->msgid);
3365 return kIOReturnBadArgument;
3366 }
3367 object = IOUserServer::target(action, message);
3368 message->objects[1] = (OSObjectRef) action;
3369 if (kIODKLogIPC & gIODKDebug) {
3370 DKLOG("%s::Dispatch(trap) kernel 0x%qx\n", object->getMetaClass()->getClassName(), message->msgid);
3371 }
3372 ret = object->Dispatch(rpc);
3373 } else {
3374 objectArg1 = NULL;
3375 if (refs > 1) {
3376 if (objectName1) {
3377 objectArg1 = iokit_lookup_uext_ref_current_task(objectName1);
3378 if (!objectArg1) {
3379 return kIOReturnIPCError;
3380 }
3381 }
3382 message->objects[1] = (OSObjectRef) objectArg1;
3383 }
3384 if (kIODKLogIPC & gIODKDebug) {
3385 DKLOG("%s::Dispatch(trap) kernel 0x%qx\n", object->getMetaClass()->getClassName(), message->msgid);
3386 }
3387 ret = object->Dispatch(rpc);
3388 if (kIODKLogIPC & gIODKDebug) {
3389 DKLOG("%s::Dispatch(trap) kernel 0x%qx 0x%x\n", object->getMetaClass()->getClassName(), message->msgid, ret);
3390 }
3391 OSSafeReleaseNULL(objectArg1);
3392
3393 if (kIOReturnSuccess == ret) {
3394 if (rpc.reply->msgh_body.msgh_descriptor_count) {
3395 return kIOReturnIPCError;
3396 }
3397 reply = IORPCMessageFromMach(rpc.reply, rpc.reply->msgh.msgh_size);
3398 if (!reply) {
3399 return kIOReturnIPCError;
3400 }
3401 copySize = rpc.reply->msgh.msgh_size - (((uintptr_t) reply) - ((uintptr_t) rpc.reply)) + sizeof(uint64_t);
3402 if (copySize > outSize) {
3403 return kIOReturnIPCError;
3404 }
3405 replyHdr = (UEXTTrapReply *) ((uintptr_t)reply - sizeof(uint64_t));
3406 replyHdr->replySize = copySize;
3407 copyerr = copyout(replyHdr, out, copySize);
3408 if (copyerr) {
3409 return kIOReturnVMError;
3410 }
3411 }
3412 }
3413
3414 return ret;
3415 }
3416
3417 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3418
3419 IOReturn
rpc(IORPC rpc)3420 IOUserServer::rpc(IORPC rpc)
3421 {
3422 if (isInactive() && !fRootQueue) {
3423 return kIOReturnOffline;
3424 }
3425
3426 IOReturn ret;
3427 IORPCMessage * message;
3428 IORPCMessageMach * mach;
3429 mach_msg_id_t machid;
3430 uint32_t sendSize, replySize;
3431 bool oneway;
3432 uint64_t msgid;
3433 IODispatchQueue * queue;
3434 IOService * service;
3435 ipc_port_t port;
3436 ipc_port_t sendPort;
3437
3438 queue = NULL;
3439 port = NULL;
3440 sendPort = NULL;
3441
3442 mach = rpc.message;
3443 sendSize = rpc.sendSize;
3444 replySize = rpc.replySize;
3445
3446 assert(sendSize >= (sizeof(IORPCMessageMach) + sizeof(IORPCMessage)));
3447
3448 message = IORPCMessageFromMach(mach, false);
3449 if (!message) {
3450 return kIOReturnIPCError;
3451 }
3452 msgid = message->msgid;
3453 machid = (msgid >> 32);
3454
3455 if (mach->msgh_body.msgh_descriptor_count < 1) {
3456 return kIOReturnNoMedia;
3457 }
3458
3459 IOLockLock(gIOUserServerLock);
3460 if ((service = OSDynamicCast(IOService, (OSObject *) message->objects[0]))) {
3461 queue = queueForObject(service, msgid);
3462 }
3463 if (!queue) {
3464 queue = fRootQueue;
3465 }
3466 if (queue && (kIODispatchQueueStopped != queue)) {
3467 port = queue->ivars->serverPort;
3468 }
3469 if (port) {
3470 sendPort = ipc_port_copy_send_mqueue(port);
3471 }
3472 IOLockUnlock(gIOUserServerLock);
3473 if (!sendPort) {
3474 return kIOReturnNotReady;
3475 }
3476
3477 oneway = (0 != (kIORPCMessageOneway & message->flags));
3478
3479 ret = copyOutObjects(mach, message, sendSize, false);
3480
3481 mach->msgh.msgh_bits = MACH_MSGH_BITS_COMPLEX |
3482 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, (oneway ? 0 : MACH_MSG_TYPE_MAKE_SEND_ONCE));
3483 mach->msgh.msgh_remote_port = sendPort;
3484 mach->msgh.msgh_local_port = (oneway ? MACH_PORT_NULL : mig_get_reply_port());
3485 mach->msgh.msgh_id = kIORPCVersionCurrent;
3486 mach->msgh.msgh_reserved = 0;
3487
3488 boolean_t message_moved;
3489
3490 if (oneway) {
3491 ret = kernel_mach_msg_send(&mach->msgh, sendSize,
3492 MACH_SEND_MSG | MACH_SEND_ALWAYS | MACH_SEND_NOIMPORTANCE,
3493 0, &message_moved);
3494 } else {
3495 assert(replySize >= (sizeof(IORPCMessageMach) + sizeof(IORPCMessage)));
3496 ret = kernel_mach_msg_rpc(&mach->msgh, sendSize, replySize, FALSE, &message_moved);
3497 }
3498
3499 ipc_port_release_send(sendPort);
3500
3501 if (MACH_MSG_SUCCESS != ret) {
3502 if (kIODKLogIPC & gIODKDebug) {
3503 DKLOG("mach_msg() failed 0x%x\n", ret);
3504 }
3505 if (!message_moved) {
3506 // release ports
3507 copyInObjects(mach, message, sendSize, false, true);
3508 }
3509 }
3510
3511 if ((KERN_SUCCESS == ret) && !oneway) {
3512 if (kIORPCVersionCurrentReply != mach->msgh.msgh_id) {
3513 ret = (MACH_NOTIFY_SEND_ONCE == mach->msgh.msgh_id) ? MIG_SERVER_DIED : MIG_REPLY_MISMATCH;
3514 } else if ((replySize = mach->msgh.msgh_size) < (sizeof(IORPCMessageMach) + sizeof(IORPCMessage))) {
3515 // printf("BAD REPLY SIZE\n");
3516 ret = MIG_BAD_ARGUMENTS;
3517 } else {
3518 if (!(MACH_MSGH_BITS_COMPLEX & mach->msgh.msgh_bits)) {
3519 mach->msgh_body.msgh_descriptor_count = 0;
3520 }
3521 message = IORPCMessageFromMach(mach, true);
3522 if (!message) {
3523 ret = kIOReturnIPCError;
3524 } else if (message->msgid != msgid) {
3525 // printf("BAD REPLY ID\n");
3526 ret = MIG_BAD_ARGUMENTS;
3527 } else {
3528 bool isError = (0 != (kIORPCMessageError & message->flags));
3529 ret = copyInObjects(mach, message, replySize, !isError, true);
3530 if (kIOReturnSuccess != ret) {
3531 if (kIODKLogIPC & gIODKDebug) {
3532 DKLOG("rpc copyin(0x%x) %x\n", ret, mach->msgh.msgh_id);
3533 }
3534 return KERN_NOT_SUPPORTED;
3535 }
3536 if (isError) {
3537 IORPCMessageErrorReturnContent * errorMsg = (typeof(errorMsg))message;
3538 ret = errorMsg->result;
3539 }
3540 }
3541 }
3542 }
3543
3544 return ret;
3545 }
3546
3547 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3548
3549 IORPCMessage *
IORPCMessageFromMach(IORPCMessageMach * msg,bool reply)3550 IORPCMessageFromMach(IORPCMessageMach * msg, bool reply)
3551 {
3552 mach_msg_size_t idx, count;
3553 mach_msg_port_descriptor_t * desc;
3554 mach_msg_port_descriptor_t * maxDesc;
3555 size_t size, msgsize;
3556 bool upgrade;
3557
3558 msgsize = msg->msgh.msgh_size;
3559 count = msg->msgh_body.msgh_descriptor_count;
3560 desc = &msg->objects[0];
3561 maxDesc = (typeof(maxDesc))(((uintptr_t) msg) + msgsize);
3562 upgrade = (msg->msgh.msgh_id != (reply ? kIORPCVersionCurrentReply : kIORPCVersionCurrent));
3563
3564 if (upgrade) {
3565 OSReportWithBacktrace("obsolete message");
3566 return NULL;
3567 }
3568
3569 for (idx = 0; idx < count; idx++) {
3570 if (desc >= maxDesc) {
3571 return NULL;
3572 }
3573 switch (desc->type) {
3574 case MACH_MSG_PORT_DESCRIPTOR:
3575 size = sizeof(mach_msg_port_descriptor_t);
3576 break;
3577 case MACH_MSG_OOL_DESCRIPTOR:
3578 size = sizeof(mach_msg_ool_descriptor_t);
3579 break;
3580 default:
3581 return NULL;
3582 }
3583 desc = (typeof(desc))(((uintptr_t) desc) + size);
3584 }
3585 return (IORPCMessage *)(uintptr_t) desc;
3586 }
3587
3588 ipc_port_t
copySendRightForObject(OSObject * object,ipc_kobject_type_t type)3589 IOUserServer::copySendRightForObject(OSObject * object, ipc_kobject_type_t type)
3590 {
3591 ipc_port_t port;
3592 ipc_port_t sendPort = NULL;
3593
3594 port = iokit_port_for_object(object, type);
3595 if (port) {
3596 sendPort = ipc_kobject_make_send(port, (ipc_kobject_t)object, type);
3597 iokit_release_port(port);
3598 }
3599
3600 return sendPort;
3601 }
3602
3603 OSObject *
copyObjectForSendRight(ipc_port_t port,ipc_kobject_type_t type)3604 IOUserServer::copyObjectForSendRight(ipc_port_t port, ipc_kobject_type_t type)
3605 {
3606 OSObject * object;
3607 object = iokit_lookup_io_object(port, type);
3608 return object;
3609 }
3610
3611 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3612
3613 // Create a vm_map_copy_t or kalloc'ed data for memory
3614 // to be copied out. ipc will free after the copyout.
3615
3616 static kern_return_t
copyoutkdata(const void * data,vm_size_t len,void ** buf)3617 copyoutkdata(const void * data, vm_size_t len, void ** buf)
3618 {
3619 kern_return_t err;
3620 vm_map_copy_t copy;
3621
3622 err = vm_map_copyin( kernel_map, CAST_USER_ADDR_T(data), len,
3623 false /* src_destroy */, ©);
3624
3625 assert( err == KERN_SUCCESS );
3626 if (err == KERN_SUCCESS) {
3627 *buf = (char *) copy;
3628 }
3629
3630 return err;
3631 }
3632
3633 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3634
3635 IOReturn
copyOutObjects(IORPCMessageMach * mach,IORPCMessage * message,size_t size,bool consume)3636 IOUserServer::copyOutObjects(IORPCMessageMach * mach, IORPCMessage * message,
3637 size_t size, bool consume)
3638 {
3639 uint64_t refs;
3640 uint32_t idx, maxObjectCount;
3641 ipc_port_t port;
3642 OSObject * object;
3643 size_t descsize;
3644 mach_msg_port_descriptor_t * desc;
3645 mach_msg_ool_descriptor_t * ool;
3646 vm_map_copy_t copy;
3647 void * address;
3648 mach_msg_size_t length;
3649 kern_return_t kr;
3650 OSSerialize * s;
3651
3652 refs = message->objectRefs;
3653 maxObjectCount = MAX_OBJECT_COUNT(mach, size, message);
3654 // assert(refs <= mach->msgh_body.msgh_descriptor_count);
3655 // assert(refs <= maxObjectCount);
3656 if (refs > mach->msgh_body.msgh_descriptor_count) {
3657 return kIOReturnBadArgument;
3658 }
3659 if (refs > maxObjectCount) {
3660 return kIOReturnBadArgument;
3661 }
3662
3663 desc = &mach->objects[0];
3664 for (idx = 0; idx < refs; idx++) {
3665 object = (OSObject *) message->objects[idx];
3666
3667 switch (desc->type) {
3668 case MACH_MSG_PORT_DESCRIPTOR:
3669 descsize = sizeof(mach_msg_port_descriptor_t);
3670 port = NULL;
3671 if (object) {
3672 #if DEVELOPMENT || DEBUG
3673 if (kIODKLogIPC & gIODKDebug) {
3674 IOMemoryDescriptor * iomd = OSDynamicCast(IOMemoryDescriptor, object);
3675 if (iomd != NULL && (iomd->getFlags() & kIOMemoryThreadSafe) == 0) {
3676 OSReportWithBacktrace("IOMemoryDescriptor %p was created without kIOMemoryThreadSafe flag", iomd);
3677 }
3678 }
3679 #endif /* DEVELOPMENT || DEBUG */
3680
3681 port = copySendRightForObject(object, IKOT_UEXT_OBJECT);
3682 if (!port) {
3683 break;
3684 }
3685 if (consume) {
3686 object->release();
3687 }
3688 message->objects[idx] = 0;
3689 }
3690 // desc->type = MACH_MSG_PORT_DESCRIPTOR;
3691 desc->disposition = MACH_MSG_TYPE_MOVE_SEND;
3692 desc->name = port;
3693 desc->pad2 = 0;
3694 desc->pad_end = 0;
3695 break;
3696
3697 case MACH_MSG_OOL_DESCRIPTOR:
3698 descsize = sizeof(mach_msg_ool_descriptor_t);
3699
3700 length = 0;
3701 address = NULL;
3702 if (object) {
3703 s = OSSerialize::binaryWithCapacity(4096);
3704 assert(s);
3705 if (!s) {
3706 break;
3707 }
3708 s->setIndexed(true);
3709 if (!object->serialize(s)) {
3710 assert(false);
3711 descsize = -1UL;
3712 s->release();
3713 break;
3714 }
3715 length = s->getLength();
3716 kr = copyoutkdata(s->text(), length, &address);
3717 s->release();
3718 if (KERN_SUCCESS != kr) {
3719 descsize = -1UL;
3720 address = NULL;
3721 length = 0;
3722 }
3723 if (consume) {
3724 object->release();
3725 }
3726 message->objects[idx] = 0;
3727 }
3728 ool = (typeof(ool))desc;
3729 // ool->type = MACH_MSG_OOL_DESCRIPTOR;
3730 ool->deallocate = false;
3731 ool->copy = MACH_MSG_PHYSICAL_COPY;
3732 ool->size = length;
3733 ool->address = address;
3734 break;
3735
3736 default:
3737 descsize = -1UL;
3738 break;
3739 }
3740 if (-1UL == descsize) {
3741 break;
3742 }
3743 desc = (typeof(desc))(((uintptr_t) desc) + descsize);
3744 }
3745
3746 if (idx >= refs) {
3747 return kIOReturnSuccess;
3748 }
3749
3750 desc = &mach->objects[0];
3751 while (idx--) {
3752 switch (desc->type) {
3753 case MACH_MSG_PORT_DESCRIPTOR:
3754 descsize = sizeof(mach_msg_port_descriptor_t);
3755 port = desc->name;
3756 if (port) {
3757 ipc_port_release_send(port);
3758 }
3759 break;
3760
3761 case MACH_MSG_OOL_DESCRIPTOR:
3762 descsize = sizeof(mach_msg_ool_descriptor_t);
3763 ool = (typeof(ool))desc;
3764 copy = (vm_map_copy_t) ool->address;
3765 if (copy) {
3766 vm_map_copy_discard(copy);
3767 }
3768 break;
3769
3770 default:
3771 descsize = -1UL;
3772 break;
3773 }
3774 if (-1UL == descsize) {
3775 break;
3776 }
3777 desc = (typeof(desc))(((uintptr_t) desc) + descsize);
3778 }
3779
3780 return kIOReturnBadArgument;
3781 }
3782
3783 IOReturn
copyInObjects(IORPCMessageMach * mach,IORPCMessage * message,size_t size,bool copyObjects,bool consumePorts)3784 IOUserServer::copyInObjects(IORPCMessageMach * mach, IORPCMessage * message,
3785 size_t size, bool copyObjects, bool consumePorts)
3786 {
3787 uint64_t refs;
3788 uint32_t idx, maxObjectCount;
3789 ipc_port_t port;
3790 OSObject * object;
3791 size_t descsize;
3792 mach_msg_port_descriptor_t * desc;
3793 mach_msg_ool_descriptor_t * ool;
3794 vm_map_address_t copyoutdata;
3795 kern_return_t kr;
3796
3797 refs = message->objectRefs;
3798 maxObjectCount = MAX_OBJECT_COUNT(mach, size, message);
3799 // assert(refs <= mach->msgh_body.msgh_descriptor_count);
3800 // assert(refs <= maxObjectCount);
3801 if (refs > mach->msgh_body.msgh_descriptor_count) {
3802 return kIOReturnBadArgument;
3803 }
3804 if (refs > maxObjectCount) {
3805 return kIOReturnBadArgument;
3806 }
3807
3808 desc = &mach->objects[0];
3809 for (idx = 0; idx < refs; idx++) {
3810 switch (desc->type) {
3811 case MACH_MSG_PORT_DESCRIPTOR:
3812 descsize = sizeof(mach_msg_port_descriptor_t);
3813
3814 object = NULL;
3815 port = desc->name;
3816 if (port) {
3817 if (copyObjects) {
3818 object = copyObjectForSendRight(port, IKOT_UEXT_OBJECT);
3819 if (!object) {
3820 descsize = -1UL;
3821 break;
3822 }
3823 }
3824 if (consumePorts) {
3825 ipc_port_release_send(port);
3826 }
3827 }
3828 break;
3829
3830 case MACH_MSG_OOL_DESCRIPTOR:
3831 descsize = sizeof(mach_msg_ool_descriptor_t);
3832 ool = (typeof(ool))desc;
3833
3834 object = NULL;
3835 if (copyObjects && ool->size && ool->address) {
3836 kr = vm_map_copyout(kernel_map, ©outdata, (vm_map_copy_t) ool->address);
3837 if (KERN_SUCCESS == kr) {
3838 object = OSUnserializeXML((const char *) copyoutdata, ool->size);
3839 kr = vm_deallocate(kernel_map, copyoutdata, ool->size);
3840 assert(KERN_SUCCESS == kr);
3841 // vm_map_copyout() has consumed the vm_map_copy_t in the message
3842 ool->size = 0;
3843 ool->address = NULL;
3844 }
3845 if (!object) {
3846 descsize = -1UL;
3847 break;
3848 }
3849 }
3850 break;
3851
3852 default:
3853 descsize = -1UL;
3854 break;
3855 }
3856 if (-1UL == descsize) {
3857 break;
3858 }
3859 if (copyObjects) {
3860 message->objects[idx] = (OSObjectRef) object;
3861 }
3862 desc = (typeof(desc))(((uintptr_t) desc) + descsize);
3863 }
3864
3865 if (idx >= refs) {
3866 return kIOReturnSuccess;
3867 }
3868
3869 while (idx--) {
3870 object = (OSObject *) message->objects[idx];
3871 OSSafeReleaseNULL(object);
3872 message->objects[idx] = 0;
3873 }
3874
3875 return kIOReturnBadArgument;
3876 }
3877
3878 IOReturn
consumeObjects(IORPCMessage * message,size_t messageSize)3879 IOUserServer::consumeObjects(IORPCMessage * message, size_t messageSize)
3880 {
3881 uint64_t refs, idx;
3882 OSObject * object;
3883
3884 refs = message->objectRefs;
3885 for (idx = 0; idx < refs; idx++) {
3886 object = (OSObject *) message->objects[idx];
3887 if (object) {
3888 object->release();
3889 message->objects[idx] = 0;
3890 }
3891 }
3892
3893 return kIOReturnSuccess;
3894 }
3895
3896 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3897
3898 static void
reboot_kernel_async_helper(thread_call_param_t p0 __unused,thread_call_param_t p1 __unused)3899 reboot_kernel_async_helper(thread_call_param_t p0 __unused, thread_call_param_t p1 __unused)
3900 {
3901 reboot_kernel(RB_AUTOBOOT, NULL);
3902 }
3903
3904 static void
reboot_kernel_async()3905 reboot_kernel_async()
3906 {
3907 thread_call_t reboot_call = thread_call_allocate(reboot_kernel_async_helper, NULL);
3908 thread_call_enter(reboot_call);
3909 }
3910
3911 bool
finalize(IOOptionBits options)3912 IOUserServer::finalize(IOOptionBits options)
3913 {
3914 OSArray * services;
3915
3916 if (kIODKLogSetup & gIODKDebug) {
3917 DKLOG("%s::finalize(%p)\n", getName(), this);
3918 }
3919
3920 IOLockLock(gIOUserServerLock);
3921 OSSafeReleaseNULL(fRootQueue);
3922 IOLockUnlock(gIOUserServerLock);
3923
3924 services = NULL;
3925 IOLockLock(fLock);
3926 if (fServices) {
3927 services = OSArray::withArray(fServices);
3928 }
3929 IOLockUnlock(fLock);
3930
3931 IOOptionBits terminateFlags = kIOServiceTerminateNeedWillTerminate | kIOServiceTerminateWithRematch;
3932 if (fCheckInToken) {
3933 bool can_rematch = fCheckInToken->dextTerminate();
3934 if (can_rematch) {
3935 terminateFlags |= kIOServiceTerminateWithRematchCurrentDext;
3936 } else {
3937 DKLOG("%s::finalize(%p) dext was replaced, do not rematch current dext\n", getName(), this);
3938 }
3939 } else {
3940 terminateFlags |= kIOServiceTerminateWithRematchCurrentDext;
3941 DKLOG("%s::finalize(%p) could not find fCheckInToken\n", getName(), this);
3942 }
3943
3944 if (services) {
3945 services->iterateObjects(^bool (OSObject * obj) {
3946 int service __unused; // hide outer defn
3947 IOService * nextService;
3948 IOService * provider;
3949 bool started = false;
3950
3951 nextService = (IOService *) obj;
3952 if (kIODKLogSetup & gIODKDebug) {
3953 DKLOG("%s::terminate(" DKS ")\n", getName(), DKN(nextService));
3954 }
3955 if (nextService->reserved->uvars) {
3956 IOUserClient * nextUserClient = OSDynamicCast(IOUserClient, nextService);
3957 provider = nextService->getProvider();
3958 if (nextUserClient) {
3959 nextUserClient->setTerminateDefer(provider, false);
3960 }
3961 started = nextService->reserved->uvars->started;
3962 nextService->reserved->uvars->serverDied = true;
3963
3964 serviceDidStop(nextService, provider);
3965 if (provider != NULL && (terminateFlags & kIOServiceTerminateWithRematchCurrentDext) == 0) {
3966 provider->resetRematchProperties();
3967 }
3968 if (started) {
3969 nextService->terminate(terminateFlags);
3970 }
3971 }
3972 if (!started) {
3973 DKLOG("%s::terminate(" DKS ") server exit before start()\n", getName(), DKN(nextService));
3974 serviceStop(nextService, NULL);
3975 }
3976 return false;
3977 });
3978 services->release();
3979 }
3980
3981 return IOUserClient::finalize(options);
3982 }
3983
3984 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3985
3986 #undef super
3987 #define super IOUserClient2022
3988
OSDefineMetaClassAndStructors(IOUserServer,IOUserClient2022)3989 OSDefineMetaClassAndStructors(IOUserServer, IOUserClient2022)
3990
3991 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3992
3993 IOUserClient * IOUserServer::withTask(task_t owningTask)
3994 {
3995 IOUserServer * inst;
3996
3997 assert(owningTask == current_task());
3998 if (!task_is_driver(owningTask)) {
3999 DKLOG("IOUserServer may only be created with driver tasks\n");
4000 return NULL;
4001 }
4002
4003 inst = new IOUserServer;
4004 if (inst && !inst->init()) {
4005 inst->release();
4006 inst = NULL;
4007 return inst;
4008 }
4009 OS_ANALYZER_SUPPRESS("82033761") inst->PMinit();
4010
4011 inst->fOwningTask = current_task();
4012 task_reference(inst->fOwningTask);
4013
4014 inst->fEntitlements = IOUserClient::copyClientEntitlements(inst->fOwningTask);
4015
4016 if (!(kIODKDisableEntitlementChecking & gIODKDebug)) {
4017 proc_t p;
4018 pid_t pid;
4019 const char * name;
4020 p = (proc_t)get_bsdtask_info(inst->fOwningTask);
4021 if (p) {
4022 name = proc_best_name(p);
4023 pid = proc_pid(p);
4024 } else {
4025 name = "unknown";
4026 pid = 0;
4027 }
4028
4029 if (inst->fEntitlements == NULL) {
4030 #if DEVELOPMENT || DEBUG
4031 panic("entitlements are missing for %s[%d]\n", name, pid);
4032 #else
4033 DKLOG("entitlements are missing for %s[%d]\n", name, pid);
4034 #endif /* DEVELOPMENT || DEBUG */
4035 }
4036
4037
4038 const char * dextTeamID = csproc_get_teamid(p);
4039 if (dextTeamID != NULL) {
4040 inst->fTeamIdentifier = OSString::withCString(dextTeamID);
4041 DKLOG("%s[%d] has team identifier %s\n", name, pid, dextTeamID);
4042 }
4043
4044 if (!IOCurrentTaskHasEntitlement(gIODriverKitEntitlementKey->getCStringNoCopy())) {
4045 IOLog(kIODriverKitEntitlementKey " entitlement check failed for %s[%d]\n", name, pid);
4046 inst->release();
4047 inst = NULL;
4048 return inst;
4049 }
4050 }
4051
4052 /* Mark the current task's space as eligible for uext object ports */
4053 iokit_label_dext_task(inst->fOwningTask);
4054
4055 inst->fLock = IOLockAlloc();
4056 inst->fServices = OSArray::withCapacity(4);
4057 inst->fClasses = OSDictionary::withCapacity(16);
4058 inst->fClasses->setOptions(OSCollection::kSort, OSCollection::kSort);
4059 inst->fPlatformDriver = task_get_platform_binary(inst->fOwningTask);
4060 if (csproc_get_validation_category(current_proc(), &inst->fCSValidationCategory) != KERN_SUCCESS) {
4061 inst->fCSValidationCategory = CS_VALIDATION_CATEGORY_INVALID;
4062 }
4063
4064 inst->setProperty(kIOUserClientDefaultLockingKey, kOSBooleanTrue);
4065 inst->setProperty(kIOUserClientDefaultLockingSetPropertiesKey, kOSBooleanTrue);
4066 inst->setProperty(kIOUserClientDefaultLockingSingleThreadExternalMethodKey, kOSBooleanTrue);
4067 //requirement for gIODriverKitEntitlementKey is enforced elsewhere conditionally
4068 inst->setProperty(kIOUserClientEntitlementsKey, kOSBooleanFalse);
4069
4070 return inst;
4071 }
4072
4073 static bool gIOUserServerLeakObjects = false;
4074
4075 bool
shouldLeakObjects()4076 IOUserServer::shouldLeakObjects()
4077 {
4078 return gIOUserServerLeakObjects;
4079 }
4080
4081 void
beginLeakingObjects()4082 IOUserServer::beginLeakingObjects()
4083 {
4084 gIOUserServerLeakObjects = true;
4085 }
4086
4087 bool
isPlatformDriver()4088 IOUserServer::isPlatformDriver()
4089 {
4090 return fPlatformDriver;
4091 }
4092
4093 int
getCSValidationCategory()4094 IOUserServer::getCSValidationCategory()
4095 {
4096 return fCSValidationCategory;
4097 }
4098
4099
4100 struct IOUserServerRecordExitReasonContext {
4101 task_t task;
4102 os_reason_t reason;
4103 };
4104
4105 static bool
IOUserServerRecordExitReasonMatch(const OSObject * obj,void * context)4106 IOUserServerRecordExitReasonMatch(const OSObject *obj, void * context)
4107 {
4108 IOUserServerRecordExitReasonContext * ctx = (IOUserServerRecordExitReasonContext *)context;
4109 IOUserServer * us = OSDynamicCast(IOUserServer, obj);
4110 if (us == NULL) {
4111 return false;
4112 }
4113
4114 if (us->fOwningTask == ctx->task) {
4115 assert(us->fTaskCrashReason == OS_REASON_NULL);
4116 assert(ctx->reason != OS_REASON_NULL);
4117 os_reason_ref(ctx->reason);
4118 us->fTaskCrashReason = ctx->reason;
4119 return true;
4120 }
4121
4122 return false;
4123 }
4124
4125 extern "C" void
IOUserServerRecordExitReason(task_t task,os_reason_t reason)4126 IOUserServerRecordExitReason(task_t task, os_reason_t reason)
4127 {
4128 IOUserServerRecordExitReasonContext ctx { task, reason };
4129 IOUserServer::gMetaClass.applyToInstances(IOUserServerRecordExitReasonMatch, &ctx);
4130 }
4131
4132 IOReturn
clientClose(void)4133 IOUserServer::clientClose(void)
4134 {
4135 OSArray * services;
4136 bool __block unexpectedExit = false;
4137 bool powerManagementFailed = false;
4138
4139 if (kIODKLogSetup & gIODKDebug) {
4140 DKLOG("%s::clientClose(%p)\n", getName(), this);
4141 }
4142
4143 services = NULL;
4144 IOLockLock(fLock);
4145 if (fServices) {
4146 services = OSArray::withArray(fServices);
4147 }
4148 powerManagementFailed = fPowerManagementFailed;
4149 IOLockUnlock(fLock);
4150
4151 // if this was a an expected exit, termination and stop should have detached at this
4152 // point, so send any provider still attached and not owned by this user server
4153 // the ClientCrashed() notification
4154 if (services) {
4155 services->iterateObjects(^bool (OSObject * obj) {
4156 int service __unused; // hide outer defn
4157 IOService * nextService;
4158 IOService * provider;
4159
4160 nextService = (IOService *) obj;
4161 if (nextService->isInactive()) {
4162 return false;
4163 }
4164 if (nextService->reserved && nextService->reserved->uvars && nextService->reserved->uvars->started) {
4165 unexpectedExit = true;
4166 }
4167 provider = nextService->getProvider();
4168 if (provider
4169 && (!provider->reserved->uvars || (provider->reserved->uvars->userServer != this))) {
4170 if (kIODKLogSetup & gIODKDebug) {
4171 DKLOG(DKS "::ClientCrashed(" DKS ")\n", DKN(provider), DKN(nextService));
4172 }
4173 provider->ClientCrashed(nextService, 0);
4174 }
4175 return false;
4176 });
4177 services->release();
4178 }
4179
4180 if (unexpectedExit &&
4181 !gInUserspaceReboot &&
4182 !powerManagementFailed &&
4183 (fTaskCrashReason == OS_REASON_NULL || (fTaskCrashReason->osr_namespace != OS_REASON_JETSAM && fTaskCrashReason->osr_namespace != OS_REASON_RUNNINGBOARD)) &&
4184 fStatistics != NULL) {
4185 OSDextCrashPolicy policy = fStatistics->recordCrash();
4186 bool allowReboot;
4187 #if DEVELOPMENT || DEBUG
4188 allowReboot = fPlatformDriver && fEntitlements->getObject(gIODriverKitTestDriverEntitlementKey) != kOSBooleanTrue && !disable_dext_crash_reboot;
4189 #else
4190 allowReboot = fPlatformDriver;
4191 #endif /* DEVELOPMENT || DEBUG */
4192
4193 if (policy == kOSDextCrashPolicyReboot && allowReboot) {
4194 IOLog("Driver %s has crashed too many times. Rebooting.\n", getName());
4195 reboot_kernel_async();
4196 }
4197 }
4198
4199 terminate();
4200 return kIOReturnSuccess;
4201 }
4202
4203 IOReturn
setProperties(OSObject * properties)4204 IOUserServer::setProperties(OSObject * properties)
4205 {
4206 IOReturn kr = kIOReturnUnsupported;
4207 return kr;
4208 }
4209
4210 void
stop(IOService * provider)4211 IOUserServer::stop(IOService * provider)
4212 {
4213 if (fOwningTask) {
4214 task_deallocate(fOwningTask);
4215 fOwningTask = TASK_NULL;
4216 }
4217
4218 PMstop();
4219
4220 IOServicePH::serverRemove(this);
4221
4222 OSSafeReleaseNULL(fRootQueue);
4223
4224 if (fInterruptLock) {
4225 IOSimpleLockFree(fInterruptLock);
4226 }
4227 }
4228
4229 void
free()4230 IOUserServer::free()
4231 {
4232 OSSafeReleaseNULL(fEntitlements);
4233 OSSafeReleaseNULL(fClasses);
4234 if (fOwningTask) {
4235 task_deallocate(fOwningTask);
4236 fOwningTask = TASK_NULL;
4237 }
4238 if (fLock) {
4239 IOLockFree(fLock);
4240 }
4241 OSSafeReleaseNULL(fServices);
4242 OSSafeReleaseNULL(fCheckInToken);
4243 OSSafeReleaseNULL(fStatistics);
4244 OSSafeReleaseNULL(fTeamIdentifier);
4245 if (fAllocationName) {
4246 kern_allocation_name_release(fAllocationName);
4247 fAllocationName = NULL;
4248 }
4249 if (fTaskCrashReason != OS_REASON_NULL) {
4250 os_reason_free(fTaskCrashReason);
4251 }
4252 IOUserClient::free();
4253 }
4254
4255 IOReturn
registerClass(OSClassDescription * desc,uint32_t size,OSUserMetaClass ** pCls)4256 IOUserServer::registerClass(OSClassDescription * desc, uint32_t size, OSUserMetaClass ** pCls)
4257 {
4258 OSUserMetaClass * cls;
4259 const OSSymbol * sym;
4260 uint64_t * methodOptions;
4261 const char * queueNames;
4262 uint32_t methodOptionsEnd, queueNamesEnd;
4263 IOReturn ret = kIOReturnSuccess;
4264
4265 if (size < sizeof(OSClassDescription)) {
4266 assert(false);
4267 return kIOReturnBadArgument;
4268 }
4269
4270 if (kIODKLogSetup & gIODKDebug) {
4271 DKLOG("%s::registerClass %s, %d, %d\n", getName(), desc->name, desc->queueNamesSize, desc->methodNamesSize);
4272 }
4273
4274 if (desc->descriptionSize != size) {
4275 assert(false);
4276 return kIOReturnBadArgument;
4277 }
4278 if (os_add_overflow(desc->queueNamesOffset, desc->queueNamesSize, &queueNamesEnd)) {
4279 assert(false);
4280 return kIOReturnBadArgument;
4281 }
4282 if (queueNamesEnd > size) {
4283 assert(false);
4284 return kIOReturnBadArgument;
4285 }
4286 if (os_add_overflow(desc->methodOptionsOffset, desc->methodOptionsSize, &methodOptionsEnd)) {
4287 assert(false);
4288 return kIOReturnBadArgument;
4289 }
4290 if (methodOptionsEnd > size) {
4291 assert(false);
4292 return kIOReturnBadArgument;
4293 }
4294 // overlaps?
4295 if ((desc->queueNamesOffset >= desc->methodOptionsOffset) && (desc->queueNamesOffset < methodOptionsEnd)) {
4296 assert(false);
4297 return kIOReturnBadArgument;
4298 }
4299 if ((queueNamesEnd >= desc->methodOptionsOffset) && (queueNamesEnd < methodOptionsEnd)) {
4300 assert(false);
4301 return kIOReturnBadArgument;
4302 }
4303
4304 if (desc->methodOptionsSize & ((2 * sizeof(uint64_t)) - 1)) {
4305 assert(false);
4306 return kIOReturnBadArgument;
4307 }
4308 if (sizeof(desc->name) == strnlen(desc->name, sizeof(desc->name))) {
4309 assert(false);
4310 return kIOReturnBadArgument;
4311 }
4312 if (sizeof(desc->superName) == strnlen(desc->superName, sizeof(desc->superName))) {
4313 assert(false);
4314 return kIOReturnBadArgument;
4315 }
4316
4317 cls = OSTypeAlloc(OSUserMetaClass);
4318 assert(cls);
4319 if (!cls) {
4320 return kIOReturnNoMemory;
4321 }
4322
4323 cls->description = (typeof(cls->description))IOMallocData(size);
4324 assert(cls->description);
4325 if (!cls->description) {
4326 assert(false);
4327 cls->release();
4328 return kIOReturnNoMemory;
4329 }
4330 bcopy(desc, cls->description, size);
4331
4332 cls->methodCount = desc->methodOptionsSize / (2 * sizeof(uint64_t));
4333 cls->methods = IONewData(uint64_t, 2 * cls->methodCount);
4334 if (!cls->methods) {
4335 assert(false);
4336 cls->release();
4337 return kIOReturnNoMemory;
4338 }
4339
4340 methodOptions = (typeof(methodOptions))(((uintptr_t) desc) + desc->methodOptionsOffset);
4341 bcopy(methodOptions, cls->methods, 2 * cls->methodCount * sizeof(uint64_t));
4342
4343 queueNames = (typeof(queueNames))(((uintptr_t) desc) + desc->queueNamesOffset);
4344 cls->queueNames = copyInStringArray(queueNames, desc->queueNamesSize);
4345
4346 sym = OSSymbol::withCString(desc->name);
4347 assert(sym);
4348 if (!sym) {
4349 assert(false);
4350 cls->release();
4351 return kIOReturnNoMemory;
4352 }
4353
4354 cls->name = sym;
4355 cls->meta = OSMetaClass::copyMetaClassWithName(sym);
4356 IOLockLock(fLock);
4357 cls->superMeta = OSDynamicCast(OSUserMetaClass, fClasses->getObject(desc->superName));
4358 if (fClasses->getObject(sym) != NULL) {
4359 /* class with this name exists */
4360 ret = kIOReturnBadArgument;
4361 } else {
4362 if (fClasses->setObject(sym, cls)) {
4363 *pCls = cls;
4364 } else {
4365 /* could not add class to fClasses */
4366 ret = kIOReturnNoMemory;
4367 }
4368 }
4369 IOLockUnlock(fLock);
4370 cls->release();
4371 return ret;
4372 }
4373
4374 IOReturn
registerClass(OSClassDescription * desc,uint32_t size,OSSharedPtr<OSUserMetaClass> & pCls)4375 IOUserServer::registerClass(OSClassDescription * desc, uint32_t size, OSSharedPtr<OSUserMetaClass>& pCls)
4376 {
4377 OSUserMetaClass* pClsRaw = NULL;
4378 IOReturn result = registerClass(desc, size, &pClsRaw);
4379 if (result == kIOReturnSuccess) {
4380 pCls.reset(pClsRaw, OSRetain);
4381 }
4382 return result;
4383 }
4384
4385 IOReturn
setRootQueue(IODispatchQueue * queue)4386 IOUserServer::setRootQueue(IODispatchQueue * queue)
4387 {
4388 assert(!fRootQueue);
4389 if (fRootQueue) {
4390 return kIOReturnStillOpen;
4391 }
4392 queue->retain();
4393 fRootQueue = queue;
4394
4395 return kIOReturnSuccess;
4396 }
4397
4398
4399 IOReturn
externalMethod(uint32_t selector,IOExternalMethodArgumentsOpaque * args)4400 IOUserServer::externalMethod(uint32_t selector, IOExternalMethodArgumentsOpaque * args)
4401 {
4402 static const IOExternalMethodDispatch2022 dispatchArray[] = {
4403 [kIOUserServerMethodRegisterClass] = {
4404 .function = &IOUserServer::externalMethodRegisterClass,
4405 .checkScalarInputCount = 0,
4406 .checkStructureInputSize = kIOUCVariableStructureSize,
4407 .checkScalarOutputCount = 2,
4408 .checkStructureOutputSize = 0,
4409 .allowAsync = false,
4410 .checkEntitlement = NULL,
4411 },
4412 [kIOUserServerMethodStart] = {
4413 .function = &IOUserServer::externalMethodStart,
4414 .checkScalarInputCount = 1,
4415 .checkStructureInputSize = 0,
4416 .checkScalarOutputCount = 1,
4417 .checkStructureOutputSize = 0,
4418 .allowAsync = false,
4419 .checkEntitlement = NULL,
4420 },
4421 };
4422
4423 return dispatchExternalMethod(selector, args, dispatchArray, sizeof(dispatchArray) / sizeof(dispatchArray[0]), this, NULL);
4424 }
4425
4426 IOReturn
externalMethodRegisterClass(OSObject * target,void * reference,IOExternalMethodArguments * args)4427 IOUserServer::externalMethodRegisterClass(OSObject * target, void * reference, IOExternalMethodArguments * args)
4428 {
4429 IOReturn ret = kIOReturnBadArgument;
4430 mach_port_name_t portname;
4431
4432 IOUserServer * me = (typeof(me))target;
4433
4434 OSUserMetaClass * cls;
4435 if (!args->structureInputSize) {
4436 return kIOReturnBadArgument;
4437 }
4438
4439 ret = me->registerClass((OSClassDescription *) args->structureInput, args->structureInputSize, &cls);
4440 if (kIOReturnSuccess == ret) {
4441 portname = iokit_make_send_right(me->fOwningTask, cls, IKOT_UEXT_OBJECT);
4442 assert(portname);
4443 args->scalarOutput[0] = portname;
4444 args->scalarOutput[1] = kOSObjectRPCRemote;
4445 }
4446
4447 return ret;
4448 }
4449
4450 IOReturn
externalMethodStart(OSObject * target,void * reference,IOExternalMethodArguments * args)4451 IOUserServer::externalMethodStart(OSObject * target, void * reference, IOExternalMethodArguments * args)
4452 {
4453 mach_port_name_t portname;
4454
4455 IOUserServer * me = (typeof(me))target;
4456
4457 if (!(kIODKDisableCheckInTokenVerification & gIODKDebug)) {
4458 mach_port_name_t checkInPortName = ((typeof(checkInPortName))args->scalarInput[0]);
4459 OSObject * obj = iokit_lookup_object_with_port_name(checkInPortName, IKOT_IOKIT_IDENT, me->fOwningTask);
4460 IOUserServerCheckInToken * retrievedToken = OSDynamicCast(IOUserServerCheckInToken, obj);
4461 if (retrievedToken != NULL) {
4462 me->setCheckInToken(retrievedToken);
4463 } else {
4464 OSSafeReleaseNULL(obj);
4465 return kIOReturnBadArgument;
4466 }
4467 OSSafeReleaseNULL(obj);
4468 }
4469 portname = iokit_make_send_right(me->fOwningTask, me, IKOT_UEXT_OBJECT);
4470 assert(portname);
4471 args->scalarOutput[0] = portname;
4472 return kIOReturnSuccess;
4473 }
4474 IOExternalTrap *
getTargetAndTrapForIndex(IOService ** targetP,UInt32 index)4475 IOUserServer::getTargetAndTrapForIndex( IOService **targetP, UInt32 index )
4476 {
4477 static const OSBoundedArray<IOExternalTrap, 1> trapTemplate = {{
4478 { NULL, (IOTrap) & IOUserServer::waitInterruptTrap},
4479 }};
4480 if (index >= trapTemplate.size()) {
4481 return NULL;
4482 }
4483 *targetP = this;
4484 return (IOExternalTrap *)&trapTemplate[index];
4485 }
4486
4487 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4488
4489 IOReturn
serviceAttach(IOService * service,IOService * provider)4490 IOUserServer::serviceAttach(IOService * service, IOService * provider)
4491 {
4492 IOReturn ret;
4493 OSObjectUserVars * vars;
4494 OSObject * prop;
4495 OSString * str;
4496 OSSymbol const* bundleID;
4497 char execPath[1024];
4498
4499 vars = IOMallocType(OSObjectUserVars);
4500 service->reserved->uvars = vars;
4501
4502 vars->userServer = this;
4503 vars->userServer->retain();
4504 vars->uvarsLock = IOLockAlloc();
4505 IOLockLock(fLock);
4506 if (-1U == fServices->getNextIndexOfObject(service, 0)) {
4507 fServices->setObject(service);
4508
4509 // Add to IOAssociatedServices
4510 OSObject * serviceArrayObj = copyProperty(gIOAssociatedServicesKey);
4511 OSArray * serviceArray = OSDynamicCast(OSArray, serviceArrayObj);
4512 if (!serviceArray) {
4513 serviceArray = OSArray::withCapacity(0);
4514 } else {
4515 serviceArray = OSDynamicCast(OSArray, serviceArray->copyCollection());
4516 assert(serviceArray != NULL);
4517 }
4518
4519 OSNumber * registryEntryNumber = OSNumber::withNumber(service->getRegistryEntryID(), 64);
4520 serviceArray->setObject(registryEntryNumber);
4521 setProperty(gIOAssociatedServicesKey, serviceArray);
4522 OSSafeReleaseNULL(registryEntryNumber);
4523 OSSafeReleaseNULL(serviceArray);
4524 OSSafeReleaseNULL(serviceArrayObj);
4525
4526 // populate kIOUserClassesKey
4527
4528 OSUserMetaClass * userMeta;
4529 OSArray * classesArray;
4530 const OSString * str2;
4531
4532 classesArray = OSArray::withCapacity(4);
4533 prop = service->copyProperty(gIOUserClassKey);
4534 str2 = OSDynamicCast(OSString, prop);
4535 userMeta = (typeof(userMeta))service->reserved->uvars->userServer->fClasses->getObject(str2);
4536 while (str2 && userMeta) {
4537 classesArray->setObject(str2);
4538 userMeta = userMeta->superMeta;
4539 if (userMeta) {
4540 str2 = userMeta->name;
4541 }
4542 }
4543 service->setProperty(gIOUserClassesKey, classesArray);
4544 OSSafeReleaseNULL(classesArray);
4545 OSSafeReleaseNULL(prop);
4546 }
4547 IOLockUnlock(fLock);
4548
4549 prop = service->copyProperty(gIOUserClassKey);
4550 str = OSDynamicCast(OSString, prop);
4551 if (str) {
4552 service->setName(str);
4553 }
4554 OSSafeReleaseNULL(prop);
4555
4556 prop = service->copyProperty(gIOModuleIdentifierKey);
4557 bundleID = OSDynamicCast(OSSymbol, prop);
4558 if (bundleID) {
4559 execPath[0] = 0;
4560 bool ok = OSKext::copyUserExecutablePath(bundleID, execPath, sizeof(execPath));
4561 if (ok) {
4562 ret = LoadModule(execPath);
4563 if (kIODKLogSetup & gIODKDebug) {
4564 DKLOG("%s::LoadModule 0x%x %s\n", getName(), ret, execPath);
4565 }
4566 }
4567 }
4568 OSSafeReleaseNULL(prop);
4569
4570 ret = kIOReturnSuccess;
4571
4572 return ret;
4573 }
4574
4575 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4576
4577 IOReturn
serviceNewUserClient(IOService * service,task_t owningTask,void * securityID,uint32_t type,OSDictionary * properties,IOUserClient ** handler)4578 IOUserServer::serviceNewUserClient(IOService * service, task_t owningTask, void * securityID,
4579 uint32_t type, OSDictionary * properties, IOUserClient ** handler)
4580 {
4581 IOReturn ret;
4582 IOUserClient * uc;
4583 IOUserUserClient * userUC;
4584 OSDictionary * entitlements;
4585 OSObject * prop;
4586 OSObject * bundleID;
4587 bool ok = false;
4588
4589 entitlements = IOUserClient::copyClientEntitlements(owningTask);
4590 if (!entitlements) {
4591 entitlements = OSDictionary::withCapacity(8);
4592 }
4593 if (entitlements) {
4594 if (kIOReturnSuccess == clientHasPrivilege((void *) owningTask, kIOClientPrivilegeAdministrator)) {
4595 entitlements->setObject(kIODriverKitUserClientEntitlementAdministratorKey, kOSBooleanTrue);
4596 }
4597 OSString * creatorName = IOCopyLogNameForPID(proc_selfpid());
4598 if (creatorName) {
4599 entitlements->setObject(kIOUserClientCreatorKey, creatorName);
4600 OSSafeReleaseNULL(creatorName);
4601 }
4602 }
4603
4604 *handler = NULL;
4605 ret = service->_NewUserClient(type, entitlements, &uc);
4606 if (kIOReturnSuccess != ret) {
4607 OSSafeReleaseNULL(entitlements);
4608 return ret;
4609 }
4610 userUC = OSDynamicCast(IOUserUserClient, uc);
4611 if (!userUC) {
4612 uc->terminate(kIOServiceTerminateNeedWillTerminate);
4613 uc->setTerminateDefer(service, false);
4614 OSSafeReleaseNULL(uc);
4615 OSSafeReleaseNULL(entitlements);
4616 return kIOReturnUnsupported;
4617 }
4618 userUC->setTask(owningTask);
4619
4620 if (!(kIODKDisableEntitlementChecking & gIODKDebug)) {
4621 do {
4622 bool checkiOS3pEntitlements;
4623
4624 // check if client has com.apple.private.driverkit.driver-access and the required entitlements match the driver's entitlements
4625 if (entitlements && (prop = entitlements->getObject(gIODriverKitRequiredEntitlementsKey))) {
4626 prop->retain();
4627 ok = checkEntitlements(fEntitlements, prop, NULL, NULL);
4628 if (ok) {
4629 break;
4630 } else {
4631 DKLOG(DKS ":UC failed required entitlement check\n", DKN(userUC));
4632 }
4633 }
4634
4635 #if XNU_TARGET_OS_IOS
4636 checkiOS3pEntitlements = !fPlatformDriver;
4637 if (checkiOS3pEntitlements && fTeamIdentifier == NULL) {
4638 DKLOG("warning: " DKS " does not have a team identifier\n", DKN(this));
4639 }
4640 #else
4641 checkiOS3pEntitlements = false;
4642 #endif
4643 if (checkiOS3pEntitlements) {
4644 // App must have com.apple.developer.driverkit.communicates-with-drivers
4645 ok = entitlements && entitlements->getObject(gIODriverKitUserClientEntitlementCommunicatesWithDriversKey) == kOSBooleanTrue;
4646 if (ok) {
4647 // check team ID
4648 const char * clientTeamID = csproc_get_teamid(current_proc());
4649 bool sameTeam = fTeamIdentifier != NULL && clientTeamID != NULL && strncmp(fTeamIdentifier->getCStringNoCopy(), clientTeamID, CS_MAX_TEAMID_LEN) == 0;
4650
4651 if (sameTeam) {
4652 ok = true;
4653 } else {
4654 // different team IDs, dext must have com.apple.developer.driverkit.allow-third-party-userclients
4655 ok = fEntitlements && fEntitlements->getObject(gIODriverKitUserClientEntitlementAllowThirdPartyUserClientsKey) == kOSBooleanTrue;
4656 }
4657 if (!ok) {
4658 DKLOG(DKS ":UC failed team ID check. client team=%s, driver team=%s\n", DKN(userUC), clientTeamID ? clientTeamID : "(null)", fTeamIdentifier ? fTeamIdentifier->getCStringNoCopy() : "(null)");
4659 }
4660 } else {
4661 DKLOG(DKS ":UC entitlement check failed, app does not have %s entitlement\n", DKN(userUC), gIODriverKitUserClientEntitlementCommunicatesWithDriversKey->getCStringNoCopy());
4662 }
4663
4664 // When checking iOS 3rd party entitlements, do not fall through to other entitlement checks
4665 break;
4666 }
4667
4668 // first party dexts and third party macOS dexts
4669
4670 // check if driver has com.apple.developer.driverkit.allow-any-userclient-access
4671 if (fEntitlements && fEntitlements->getObject(gIODriverKitUserClientEntitlementAllowAnyKey)) {
4672 ok = true;
4673 break;
4674 }
4675
4676 // check if client has com.apple.developer.driverkit.userclient-access and its value matches the bundle ID of the service
4677 bundleID = service->copyProperty(gIOModuleIdentifierKey);
4678 ok = (entitlements
4679 && bundleID
4680 && (prop = entitlements->getObject(gIODriverKitUserClientEntitlementsKey)));
4681 if (ok) {
4682 bool found __block = false;
4683 ok = prop->iterateObjects(^bool (OSObject * object) {
4684 found = object->isEqualTo(bundleID);
4685 return found;
4686 });
4687 ok = found;
4688 } else {
4689 OSString * bundleIDStr = OSDynamicCast(OSString, bundleID);
4690 DKLOG(DKS ":UC failed userclient-access check, needed bundle ID %s\n", DKN(userUC), bundleIDStr ? bundleIDStr->getCStringNoCopy() : "(null)");
4691 }
4692 OSSafeReleaseNULL(bundleID);
4693 } while (false);
4694
4695 if (ok) {
4696 prop = userUC->copyProperty(gIOServiceDEXTEntitlementsKey);
4697 ok = checkEntitlements(entitlements, prop, NULL, NULL);
4698 }
4699
4700 if (!ok) {
4701 DKLOG(DKS ":UC entitlements check failed\n", DKN(userUC));
4702 uc->terminate(kIOServiceTerminateNeedWillTerminate);
4703 uc->setTerminateDefer(service, false);
4704 OSSafeReleaseNULL(uc);
4705 OSSafeReleaseNULL(entitlements);
4706 return kIOReturnNotPermitted;
4707 }
4708 }
4709
4710 OSSafeReleaseNULL(entitlements);
4711 *handler = userUC;
4712
4713 return ret;
4714 }
4715
4716 IOReturn
serviceNewUserClient(IOService * service,task_t owningTask,void * securityID,uint32_t type,OSDictionary * properties,OSSharedPtr<IOUserClient> & handler)4717 IOUserServer::serviceNewUserClient(IOService * service, task_t owningTask, void * securityID,
4718 uint32_t type, OSDictionary * properties, OSSharedPtr<IOUserClient>& handler)
4719 {
4720 IOUserClient* handlerRaw = NULL;
4721 IOReturn result = serviceNewUserClient(service, owningTask, securityID, type, properties, &handlerRaw);
4722 handler.reset(handlerRaw, OSNoRetain);
4723 return result;
4724 }
4725
4726 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4727
4728 static IOPMPowerState
4729 sPowerStates[] = {
4730 { .version = kIOPMPowerStateVersion1,
4731 .capabilityFlags = 0,
4732 .outputPowerCharacter = 0,
4733 .inputPowerRequirement = 0},
4734 { .version = kIOPMPowerStateVersion1,
4735 .capabilityFlags = kIOPMLowPower,
4736 .outputPowerCharacter = kIOPMLowPower,
4737 .inputPowerRequirement = kIOPMLowPower},
4738 { .version = kIOPMPowerStateVersion1,
4739 .capabilityFlags = kIOPMPowerOn,
4740 .outputPowerCharacter = kIOPMPowerOn,
4741 .inputPowerRequirement = kIOPMPowerOn},
4742 };
4743
4744 enum {
4745 kUserServerMaxPowerState = 2
4746 };
4747
4748 IOReturn
serviceJoinPMTree(IOService * service)4749 IOUserServer::serviceJoinPMTree(IOService * service)
4750 {
4751 IOReturn ret;
4752 IOService * pmProvider;
4753 bool joinTree;
4754
4755 if (service->reserved->uvars->userServerPM) {
4756 return kIOReturnSuccess;
4757 }
4758
4759 if (!fRootNotifier) {
4760 ret = registerPowerDriver(this, sPowerStates, sizeof(sPowerStates) / sizeof(sPowerStates[0]));
4761 assert(kIOReturnSuccess == ret);
4762 IOServicePH::serverAdd(this);
4763 fRootNotifier = true;
4764 }
4765
4766 joinTree = false;
4767 if (!(kIODKDisablePM & gIODKDebug) && !service->pm_vars) {
4768 kern_return_t kr;
4769 OSDictionary * props;
4770 kr = service->CopyProperties_Local(&props);
4771 if (kIOReturnSuccess == kr) {
4772 if (props->getObject(kIOPMResetPowerStateOnWakeKey) == kOSBooleanTrue) {
4773 service->setProperty(kIOPMResetPowerStateOnWakeKey, kOSBooleanTrue);
4774 }
4775 OSSafeReleaseNULL(props);
4776 }
4777 service->PMinit();
4778 ret = service->registerPowerDriver(this, sPowerStates, sizeof(sPowerStates) / sizeof(sPowerStates[0]));
4779 assert(kIOReturnSuccess == ret);
4780 joinTree = true;
4781 }
4782
4783 pmProvider = service;
4784 while (pmProvider && !pmProvider->inPlane(gIOPowerPlane)) {
4785 pmProvider = pmProvider->getProvider();
4786 }
4787 if (!pmProvider) {
4788 pmProvider = getPMRootDomain();
4789 }
4790 if (pmProvider) {
4791 IOService * entry;
4792 OSObject * prop;
4793 OSObject * nextProp;
4794 OSString * str;
4795
4796 entry = pmProvider;
4797 prop = NULL;
4798 do {
4799 nextProp = entry->copyProperty("non-removable");
4800 if (nextProp) {
4801 OSSafeReleaseNULL(prop);
4802 prop = nextProp;
4803 }
4804 entry = entry->getProvider();
4805 } while (entry);
4806 if (prop) {
4807 str = OSDynamicCast(OSString, prop);
4808 if (str && str->isEqualTo("yes")) {
4809 pmProvider = NULL;
4810 }
4811 prop->release();
4812 }
4813 }
4814
4815 if (!(kIODKDisablePM & gIODKDebug) && pmProvider) {
4816 IOLockLock(fLock);
4817 service->reserved->uvars->powerState = true;
4818 IOLockUnlock(fLock);
4819
4820 if (joinTree) {
4821 pmProvider->joinPMtree(service);
4822 service->reserved->uvars->userServerPM = true;
4823 service->reserved->uvars->resetPowerOnWake = service->propertyExists(kIOPMResetPowerStateOnWakeKey);
4824 }
4825 }
4826
4827 service->registerInterestedDriver(this);
4828 return kIOReturnSuccess;
4829 }
4830
4831 IOReturn
setPowerState(unsigned long state,IOService * service)4832 IOUserServer::setPowerState(unsigned long state, IOService * service)
4833 {
4834 if (kIODKLogPM & gIODKDebug) {
4835 DKLOG(DKS "::setPowerState(%ld) %d\n", DKN(service), state, fSystemPowerAck);
4836 }
4837 return kIOPMAckImplied;
4838 }
4839
4840 void
setPowerManagementFailed(bool failed)4841 IOUserServer::setPowerManagementFailed(bool failed)
4842 {
4843 IOLockLock(fLock);
4844 fPowerManagementFailed = failed;
4845 IOLockUnlock(fLock);
4846 }
4847
4848 IOReturn
serviceSetPowerState(IOService * controllingDriver,IOService * service,IOPMPowerFlags flags,unsigned long state)4849 IOUserServer::serviceSetPowerState(IOService * controllingDriver, IOService * service, IOPMPowerFlags flags, unsigned long state)
4850 {
4851 IOReturn ret;
4852 bool sendIt = false;
4853
4854 IOLockLock(fLock);
4855 if (service->reserved->uvars) {
4856 if (!fSystemOff && !fPowerManagementFailed && !(kIODKDisablePM & gIODKDebug)) {
4857 OSDictionary * wakeDescription;
4858 OSObject * prop;
4859 char wakeReasonString[128];
4860
4861 wakeDescription = OSDictionary::withCapacity(4);
4862 if (wakeDescription) {
4863 wakeReasonString[0] = 0;
4864 getPMRootDomain()->copyWakeReasonString(wakeReasonString, sizeof(wakeReasonString));
4865
4866 if (wakeReasonString[0]) {
4867 prop = OSString::withCString(&wakeReasonString[0]);
4868 wakeDescription->setObject(gIOSystemStateWakeDescriptionWakeReasonKey, prop);
4869 OSSafeReleaseNULL(prop);
4870 }
4871 getSystemStateNotificationService()->StateNotificationItemSet(gIOSystemStateWakeDescriptionKey, wakeDescription);
4872 OSSafeReleaseNULL(wakeDescription);
4873 }
4874
4875 service->reserved->uvars->willPower = true;
4876 service->reserved->uvars->willPowerState = state;
4877 service->reserved->uvars->controllingDriver = controllingDriver;
4878 sendIt = true;
4879 } else {
4880 service->reserved->uvars->willPower = false;
4881 }
4882 }
4883 IOLockUnlock(fLock);
4884
4885 if (sendIt) {
4886 if (kIODKLogPM & gIODKDebug) {
4887 DKLOG(DKS "::serviceSetPowerState(%ld) %d\n", DKN(service), state, fSystemPowerAck);
4888 }
4889 ret = service->SetPowerState((uint32_t) flags);
4890 if (kIOReturnSuccess == ret) {
4891 return 20 * 1000 * 1000;
4892 } else {
4893 IOLockLock(fLock);
4894 service->reserved->uvars->willPower = false;
4895 IOLockUnlock(fLock);
4896 }
4897 }
4898
4899 return kIOPMAckImplied;
4900 }
4901
4902 IOReturn
powerStateWillChangeTo(IOPMPowerFlags flags,unsigned long state,IOService * service)4903 IOUserServer::powerStateWillChangeTo(IOPMPowerFlags flags, unsigned long state, IOService * service)
4904 {
4905 return kIOPMAckImplied;
4906 }
4907
4908 IOReturn
powerStateDidChangeTo(IOPMPowerFlags flags,unsigned long state,IOService * service)4909 IOUserServer::powerStateDidChangeTo(IOPMPowerFlags flags, unsigned long state, IOService * service)
4910 {
4911 unsigned int idx;
4912 bool pmAck;
4913
4914 pmAck = false;
4915 IOLockLock(fLock);
4916 idx = fServices->getNextIndexOfObject(service, 0);
4917 if (-1U == idx) {
4918 IOLockUnlock(fLock);
4919 return kIOPMAckImplied;
4920 }
4921
4922 service->reserved->uvars->powerState = (0 != state);
4923 bool allPowerStates __block = service->reserved->uvars->powerState;
4924 if (!allPowerStates) {
4925 // any service on?
4926 fServices->iterateObjects(^bool (OSObject * obj) {
4927 int service __unused; // hide outer defn
4928 IOService * nextService;
4929 nextService = (IOService *) obj;
4930 allPowerStates = nextService->reserved->uvars->powerState;
4931 // early terminate if true
4932 return allPowerStates;
4933 });
4934 }
4935 if (kIODKLogPM & gIODKDebug) {
4936 DKLOG(DKS "::powerStateDidChangeTo(%ld) %d, %d\n", DKN(service), state, allPowerStates, fSystemPowerAck);
4937 }
4938 if (!allPowerStates && (pmAck = fSystemPowerAck)) {
4939 fSystemPowerAck = false;
4940 fSystemOff = true;
4941 }
4942 IOLockUnlock(fLock);
4943
4944 if (pmAck) {
4945 IOServicePH::serverAck(this);
4946 }
4947
4948 return kIOPMAckImplied;
4949 }
4950
4951 kern_return_t
JoinPMTree_Impl(void)4952 IOService::JoinPMTree_Impl(void)
4953 {
4954 if (!reserved->uvars || !reserved->uvars->userServer) {
4955 return kIOReturnNotReady;
4956 }
4957 return reserved->uvars->userServer->serviceJoinPMTree(this);
4958 }
4959
4960 kern_return_t
SetPowerState_Impl(uint32_t powerFlags)4961 IOService::SetPowerState_Impl(
4962 uint32_t powerFlags)
4963 {
4964 if (kIODKLogPM & gIODKDebug) {
4965 DKLOG(DKS "::SetPowerState(%d), %d\n", DKN(this), powerFlags, reserved->uvars->willPower);
4966 }
4967 if (reserved->uvars
4968 && reserved->uvars->userServer
4969 && reserved->uvars->willPower) {
4970 IOReturn ret;
4971 reserved->uvars->willPower = false;
4972 ret = reserved->uvars->controllingDriver->setPowerState(reserved->uvars->willPowerState, this);
4973 if (kIOPMAckImplied == ret) {
4974 acknowledgeSetPowerState();
4975 }
4976 return kIOReturnSuccess;
4977 }
4978 return kIOReturnNotReady;
4979 }
4980
4981 kern_return_t
ChangePowerState_Impl(uint32_t powerFlags)4982 IOService::ChangePowerState_Impl(
4983 uint32_t powerFlags)
4984 {
4985 switch (powerFlags) {
4986 case kIOServicePowerCapabilityOff:
4987 changePowerStateToPriv(0);
4988 break;
4989 case kIOServicePowerCapabilityLow:
4990 changePowerStateToPriv(1);
4991 break;
4992 case kIOServicePowerCapabilityOn:
4993 changePowerStateToPriv(2);
4994 break;
4995 default:
4996 return kIOReturnBadArgument;
4997 }
4998
4999 return kIOReturnSuccess;
5000 }
5001
5002 kern_return_t
_ClaimSystemWakeEvent_Impl(IOService * device,uint64_t flags,const char * reason,OSContainer * details)5003 IOService::_ClaimSystemWakeEvent_Impl(
5004 IOService * device,
5005 uint64_t flags,
5006 const char * reason,
5007 OSContainer * details)
5008 {
5009 IOPMrootDomain * rootDomain;
5010 IOOptionBits pmFlags;
5011
5012 rootDomain = getPMRootDomain();
5013 if (!rootDomain) {
5014 return kIOReturnNotReady;
5015 }
5016 if (os_convert_overflow(flags, &pmFlags)) {
5017 return kIOReturnBadArgument;
5018 }
5019 rootDomain->claimSystemWakeEvent(device, pmFlags, reason, details);
5020
5021 return kIOReturnSuccess;
5022 }
5023
5024 kern_return_t
Create_Impl(IOService * provider,const char * propertiesKey,IOService ** result)5025 IOService::Create_Impl(
5026 IOService * provider,
5027 const char * propertiesKey,
5028 IOService ** result)
5029 {
5030 OSObject * inst;
5031 IOService * service;
5032 OSString * str;
5033 const OSSymbol * sym;
5034 OSObject * prop = NULL;
5035 OSObject * moduleIdentifier = NULL;
5036 OSObject * userServerName = NULL;
5037 OSDictionary * properties = NULL;
5038 OSDictionary * copyProperties = NULL;
5039 kern_return_t ret;
5040
5041 if (provider != this) {
5042 return kIOReturnUnsupported;
5043 }
5044
5045 ret = kIOReturnUnsupported;
5046 inst = NULL;
5047 service = NULL;
5048
5049 prop = copyProperty(propertiesKey);
5050 properties = OSDynamicCast(OSDictionary, prop);
5051 if (!properties) {
5052 ret = kIOReturnBadArgument;
5053 goto finish;
5054 }
5055 copyProperties = OSDynamicCast(OSDictionary, properties->copyCollection());
5056 if (!copyProperties) {
5057 ret = kIOReturnNoMemory;
5058 goto finish;
5059 }
5060 moduleIdentifier = copyProperty(gIOModuleIdentifierKey);
5061 if (moduleIdentifier) {
5062 copyProperties->setObject(gIOModuleIdentifierKey, moduleIdentifier);
5063 }
5064 userServerName = reserved->uvars->userServer->copyProperty(gIOUserServerNameKey);
5065 if (userServerName) {
5066 copyProperties->setObject(gIOUserServerNameKey, userServerName);
5067 }
5068
5069 str = OSDynamicCast(OSString, copyProperties->getObject(gIOClassKey));
5070 if (!str) {
5071 ret = kIOReturnBadArgument;
5072 goto finish;
5073 }
5074 sym = OSSymbol::withString(str);
5075 if (sym) {
5076 inst = OSMetaClass::allocClassWithName(sym);
5077 service = OSDynamicCast(IOService, inst);
5078 if (service && service->init(copyProperties) && service->attach(this)) {
5079 reserved->uvars->userServer->serviceAttach(service, this);
5080 service->reserved->uvars->started = true;
5081 ret = kIOReturnSuccess;
5082 *result = service;
5083 }
5084 OSSafeReleaseNULL(sym);
5085 }
5086
5087 finish:
5088 OSSafeReleaseNULL(prop);
5089 OSSafeReleaseNULL(copyProperties);
5090 OSSafeReleaseNULL(moduleIdentifier);
5091 OSSafeReleaseNULL(userServerName);
5092 if (kIOReturnSuccess != ret) {
5093 OSSafeReleaseNULL(inst);
5094 }
5095
5096 return ret;
5097 }
5098
5099 kern_return_t
Terminate_Impl(uint64_t options)5100 IOService::Terminate_Impl(
5101 uint64_t options)
5102 {
5103 IOUserServer * us;
5104
5105 if (options) {
5106 return kIOReturnUnsupported;
5107 }
5108
5109 us = (typeof(us))thread_iokit_tls_get(0);
5110 if (us && (!reserved->uvars
5111 || (reserved->uvars->userServer != us))) {
5112 return kIOReturnNotPermitted;
5113 }
5114 terminate(kIOServiceTerminateNeedWillTerminate);
5115
5116 return kIOReturnSuccess;
5117 }
5118
5119 kern_return_t
NewUserClient_Impl(uint32_t type,IOUserClient ** userClient)5120 IOService::NewUserClient_Impl(
5121 uint32_t type,
5122 IOUserClient ** userClient)
5123 {
5124 return kIOReturnError;
5125 }
5126
5127 kern_return_t
_NewUserClient_Impl(uint32_t type,OSDictionary * entitlements,IOUserClient ** userClient)5128 IOService::_NewUserClient_Impl(
5129 uint32_t type,
5130 OSDictionary * entitlements,
5131 IOUserClient ** userClient)
5132 {
5133 return kIOReturnError;
5134 }
5135
5136 kern_return_t
SearchProperty_Impl(const char * name,const char * plane,uint64_t options,OSContainer ** property)5137 IOService::SearchProperty_Impl(
5138 const char * name,
5139 const char * plane,
5140 uint64_t options,
5141 OSContainer ** property)
5142 {
5143 OSObject * object __block;
5144 IOService * provider;
5145 IOOptionBits regOptions;
5146
5147 if (kIOServiceSearchPropertyParents & options) {
5148 regOptions = kIORegistryIterateParents | kIORegistryIterateRecursively;
5149 } else {
5150 regOptions = 0;
5151 }
5152
5153 object = copyProperty(name, IORegistryEntry::getPlane(plane), regOptions);
5154
5155 if (NULL == object) {
5156 for (provider = this; provider; provider = provider->getProvider()) {
5157 provider->runPropertyActionBlock(^IOReturn (void) {
5158 OSDictionary * userProps;
5159 object = provider->getProperty(name);
5160 if (!object
5161 && (userProps = OSDynamicCast(OSDictionary, provider->getProperty(gIOUserServicePropertiesKey)))) {
5162 object = userProps->getObject(name);
5163 }
5164 if (object) {
5165 object->retain();
5166 }
5167 return kIOReturnSuccess;
5168 });
5169 if (object || !(kIORegistryIterateParents & options)) {
5170 break;
5171 }
5172 }
5173 }
5174
5175 *property = object;
5176
5177 return object ? kIOReturnSuccess : kIOReturnNotFound;
5178 }
5179
5180 kern_return_t
StringFromReturn_Impl(IOReturn retval,OSString ** str)5181 IOService::StringFromReturn_Impl(
5182 IOReturn retval,
5183 OSString ** str)
5184 {
5185 OSString *obj = OSString::withCString(stringFromReturn(retval));
5186 *str = obj;
5187 return obj ? kIOReturnSuccess : kIOReturnError;
5188 }
5189
5190 #if PRIVATE_WIFI_ONLY
5191 const char *
StringFromReturn(IOReturn retval)5192 IOService::StringFromReturn(
5193 IOReturn retval)
5194 {
5195 return stringFromReturn(retval);
5196 }
5197 #endif /* PRIVATE_WIFI_ONLY */
5198
5199 kern_return_t
CopyProviderProperties_Impl(OSArray * propertyKeys,OSArray ** properties)5200 IOService::CopyProviderProperties_Impl(
5201 OSArray * propertyKeys,
5202 OSArray ** properties)
5203 {
5204 IOReturn ret;
5205 OSArray * result;
5206 IOService * provider;
5207
5208 result = OSArray::withCapacity(8);
5209 if (!result) {
5210 return kIOReturnNoMemory;
5211 }
5212
5213 ret = kIOReturnSuccess;
5214 for (provider = this; provider; provider = provider->getProvider()) {
5215 OSObject * obj;
5216 OSDictionary * props;
5217
5218 obj = provider->copyProperty(gIOSupportedPropertiesKey);
5219 props = OSDynamicCast(OSDictionary, obj);
5220 if (!props) {
5221 OSSafeReleaseNULL(obj);
5222 props = provider->dictionaryWithProperties();
5223 }
5224 if (!props) {
5225 ret = kIOReturnNoMemory;
5226 break;
5227 }
5228
5229 bool __block addClass = true;
5230 if (propertyKeys) {
5231 OSDictionary * retProps;
5232 retProps = OSDictionary::withCapacity(4);
5233 addClass = false;
5234 if (!retProps) {
5235 ret = kIOReturnNoMemory;
5236 OSSafeReleaseNULL(props);
5237 break;
5238 }
5239 propertyKeys->iterateObjects(^bool (OSObject * _key) {
5240 OSString * key = OSDynamicCast(OSString, _key);
5241 if (gIOClassKey->isEqualTo(key)) {
5242 addClass = true;
5243 return false;
5244 }
5245 retProps->setObject(key, props->getObject(key));
5246 return false;
5247 });
5248 OSSafeReleaseNULL(props);
5249 props = retProps;
5250 }
5251 if (addClass) {
5252 OSArray * classes = OSArray::withCapacity(8);
5253 if (!classes) {
5254 OSSafeReleaseNULL(props);
5255 ret = kIOReturnNoMemory;
5256 break;
5257 }
5258 for (const OSMetaClass * meta = provider->getMetaClass(); meta; meta = meta->getSuperClass()) {
5259 classes->setObject(meta->getClassNameSymbol());
5260 }
5261 props->setObject(gIOClassKey, classes);
5262 OSSafeReleaseNULL(classes);
5263 }
5264 bool ok = result->setObject(props);
5265 props->release();
5266 if (!ok) {
5267 ret = kIOReturnNoMemory;
5268 break;
5269 }
5270 }
5271 if (kIOReturnSuccess != ret) {
5272 OSSafeReleaseNULL(result);
5273 }
5274 *properties = result;
5275 return ret;
5276 }
5277
5278 IOReturn
AdjustBusy_Impl(int32_t delta)5279 IOService::AdjustBusy_Impl(int32_t delta)
5280 {
5281 adjustBusy(delta);
5282 return kIOReturnSuccess;
5283 }
5284
5285 IOReturn
GetBusyState_Impl(uint32_t * busyState)5286 IOService::GetBusyState_Impl(uint32_t *busyState)
5287 {
5288 *busyState = getBusyState();
5289 return kIOReturnSuccess;
5290 }
5291
5292 void
systemPower(bool powerOff)5293 IOUserServer::systemPower(bool powerOff)
5294 {
5295 OSArray * services;
5296 {
5297 OSDictionary * sleepDescription;
5298 OSObject * prop;
5299
5300 sleepDescription = OSDictionary::withCapacity(4);
5301 if (sleepDescription) {
5302 prop = getPMRootDomain()->copyProperty(kRootDomainSleepReasonKey);
5303 if (prop) {
5304 sleepDescription->setObject(gIOSystemStateSleepDescriptionReasonKey, prop);
5305 OSSafeReleaseNULL(prop);
5306 }
5307 prop = getPMRootDomain()->copyProperty(kIOHibernateStateKey);
5308 if (prop) {
5309 sleepDescription->setObject(gIOSystemStateSleepDescriptionHibernateStateKey, prop);
5310 OSSafeReleaseNULL(prop);
5311 }
5312 getSystemStateNotificationService()->StateNotificationItemSet(gIOSystemStateSleepDescriptionKey, sleepDescription);
5313 OSSafeReleaseNULL(sleepDescription);
5314 }
5315 }
5316
5317 IOLockLock(fLock);
5318
5319 if (fPowerManagementFailed && !powerOff) {
5320 IOLockUnlock(fLock);
5321 kill("Power Management Failed");
5322 return;
5323 }
5324
5325 services = OSArray::withArray(fServices);
5326
5327 bool allPowerStates __block = 0;
5328 // any service on?
5329 fServices->iterateObjects(^bool (OSObject * obj) {
5330 int service __unused; // hide outer defn
5331 IOService * nextService;
5332 nextService = (IOService *) obj;
5333 allPowerStates = nextService->reserved->uvars->powerState;
5334 // early terminate if true
5335 return allPowerStates;
5336 });
5337
5338 if (kIODKLogPM & gIODKDebug) {
5339 DKLOG("%s::powerOff(%d) %d\n", getName(), powerOff, allPowerStates);
5340 }
5341
5342 if (powerOff) {
5343 fSystemPowerAck = allPowerStates;
5344 if (!fSystemPowerAck) {
5345 fSystemOff = true;
5346 }
5347 IOLockUnlock(fLock);
5348
5349 if (!fSystemPowerAck) {
5350 IOServicePH::serverAck(this);
5351 } else {
5352 if (services) {
5353 services->iterateObjects(^bool (OSObject * obj) {
5354 int service __unused; // hide outer defn
5355 IOService * nextService;
5356 nextService = (IOService *) obj;
5357 if (kIODKLogPM & gIODKDebug) {
5358 DKLOG("changePowerStateWithOverrideTo(" DKS ", %d)\n", DKN(nextService), 0);
5359 }
5360 nextService->reserved->uvars->powerOverride = nextService->reserved->uvars->userServerPM ? kUserServerMaxPowerState : nextService->getPowerState();
5361 nextService->changePowerStateWithOverrideTo(0, 0);
5362 return false;
5363 });
5364 }
5365 }
5366 } else {
5367 fSystemOff = false;
5368 IOLockUnlock(fLock);
5369 if (services) {
5370 services->iterateObjects(^bool (OSObject * obj) {
5371 int service __unused; // hide outer defn
5372 IOService * nextService;
5373 nextService = (IOService *) obj;
5374 if (-1U != nextService->reserved->uvars->powerOverride) {
5375 if (kIODKLogPM & gIODKDebug) {
5376 DKLOG("%schangePowerStateWithOverrideTo(" DKS ", %d)\n", nextService->reserved->uvars->resetPowerOnWake ? "!" : "", DKN(nextService), nextService->reserved->uvars->powerOverride);
5377 }
5378 if (!nextService->reserved->uvars->resetPowerOnWake) {
5379 nextService->changePowerStateWithOverrideTo(nextService->reserved->uvars->powerOverride, 0);
5380 }
5381 nextService->reserved->uvars->powerOverride = -1U;
5382 }
5383 return false;
5384 });
5385 }
5386 }
5387 OSSafeReleaseNULL(services);
5388 }
5389
5390
5391 void
systemHalt(int howto)5392 IOUserServer::systemHalt(int howto)
5393 {
5394 OSArray * services;
5395
5396 if (true || (kIODKLogPM & gIODKDebug)) {
5397 DKLOG("%s::systemHalt()\n", getName());
5398 }
5399
5400 {
5401 OSDictionary * haltDescription;
5402 OSNumber * state;
5403 uint64_t haltStateFlags;
5404
5405 haltDescription = OSDictionary::withCapacity(4);
5406 if (haltDescription) {
5407 haltStateFlags = 0;
5408 if (RB_HALT & howto) {
5409 haltStateFlags |= kIOServiceHaltStatePowerOff;
5410 } else {
5411 haltStateFlags |= kIOServiceHaltStateRestart;
5412 }
5413 state = OSNumber::withNumber(haltStateFlags, 64);
5414 haltDescription->setObject(gIOSystemStateHaltDescriptionHaltStateKey, state);
5415 getSystemStateNotificationService()->StateNotificationItemSet(gIOSystemStateHaltDescriptionKey, haltDescription);
5416
5417 OSSafeReleaseNULL(state);
5418 OSSafeReleaseNULL(haltDescription);
5419 }
5420 }
5421
5422 IOLockLock(fLock);
5423 services = OSArray::withArray(fServices);
5424 IOLockUnlock(fLock);
5425
5426 if (services) {
5427 services->iterateObjects(^bool (OSObject * obj) {
5428 int service __unused; // hide outer defn
5429 IOService * nextService;
5430 IOService * provider;
5431 IOOptionBits terminateOptions;
5432 bool root;
5433
5434 nextService = (IOService *) obj;
5435 provider = nextService->getProvider();
5436 if (!provider) {
5437 DKLOG("stale service " DKS " found, skipping termination\n", DKN(nextService));
5438 return false;
5439 }
5440 root = (NULL == provider->getProperty(gIOUserServerNameKey, gIOServicePlane));
5441 if (true || (kIODKLogPM & gIODKDebug)) {
5442 DKLOG("%d: terminate(" DKS ")\n", root, DKN(nextService));
5443 }
5444 if (!root) {
5445 return false;
5446 }
5447 terminateOptions = kIOServiceRequired | kIOServiceTerminateNeedWillTerminate;
5448 if (!nextService->terminate(terminateOptions)) {
5449 IOLog("failed to terminate service %s-0x%llx\n", nextService->getName(), nextService->getRegistryEntryID());
5450 }
5451 return false;
5452 });
5453 }
5454 OSSafeReleaseNULL(services);
5455 }
5456
5457 void
powerSourceChanged(bool acAttached)5458 IOUserServer::powerSourceChanged(bool acAttached)
5459 {
5460 OSDictionary * powerSourceDescription;
5461
5462 powerSourceDescription = OSDictionary::withCapacity(4);
5463 if (!powerSourceDescription) {
5464 return;
5465 }
5466 powerSourceDescription->setObject(gIOSystemStatePowerSourceDescriptionACAttachedKey, acAttached ? kOSBooleanTrue : kOSBooleanFalse);
5467 getSystemStateNotificationService()->StateNotificationItemSet(gIOSystemStatePowerSourceDescriptionKey, powerSourceDescription);
5468
5469 OSSafeReleaseNULL(powerSourceDescription);
5470 }
5471
5472 IOReturn
serviceStarted(IOService * service,IOService * provider,bool result)5473 IOUserServer::serviceStarted(IOService * service, IOService * provider, bool result)
5474 {
5475 IOReturn ret;
5476
5477 DKLOG(DKS "::start(" DKS ") %s\n", DKN(service), DKN(provider), result ? "ok" : "fail");
5478
5479 if (!result) {
5480 ret = kIOReturnSuccess;
5481 return ret;
5482 }
5483
5484 ret = serviceJoinPMTree(service);
5485
5486 service->reserved->uvars->started = true;
5487
5488 if (service->reserved->uvars->deferredRegisterService) {
5489 service->registerService(kIOServiceAsynchronous);
5490 service->reserved->uvars->deferredRegisterService = false;
5491 }
5492
5493 return kIOReturnSuccess;
5494 }
5495
5496
5497 IOReturn
serviceOpen(IOService * provider,IOService * client)5498 IOUserServer::serviceOpen(IOService * provider, IOService * client)
5499 {
5500 OSObjectUserVars * uvars;
5501 IOReturn ret;
5502
5503 IOLockLock(client->reserved->uvars->uvarsLock);
5504 uvars = client->reserved->uvars;
5505 if (uvars->willTerminate || uvars->stopped) {
5506 DKLOG(DKS "- " DKS " blocked attempt to open " DKS "\n", DKN(this), DKN(client), DKN(provider));
5507 ret = kIOReturnBadArgument;
5508 } else {
5509 if (!uvars->openProviders) {
5510 uvars->openProviders = OSArray::withObjects((const OSObject **) &provider, 1);
5511 } else if (-1U == uvars->openProviders->getNextIndexOfObject(provider, 0)) {
5512 uvars->openProviders->setObject(provider);
5513 }
5514 ret = kIOReturnSuccess;
5515 }
5516
5517 IOLockUnlock(client->reserved->uvars->uvarsLock);
5518
5519 return ret;
5520 }
5521
5522 IOReturn
serviceClose(IOService * provider,IOService * client)5523 IOUserServer::serviceClose(IOService * provider, IOService * client)
5524 {
5525 OSObjectUserVars * uvars;
5526 unsigned int idx;
5527 IOReturn ret;
5528
5529 IOLockLock(client->reserved->uvars->uvarsLock);
5530 uvars = client->reserved->uvars;
5531 if (!uvars->openProviders) {
5532 ret = kIOReturnNotOpen;
5533 goto finish;
5534 }
5535 idx = uvars->openProviders->getNextIndexOfObject(provider, 0);
5536 if (-1U == idx) {
5537 ret = kIOReturnNotOpen;
5538 goto finish;
5539 }
5540 uvars->openProviders->removeObject(idx);
5541 if (!uvars->openProviders->getCount()) {
5542 OSSafeReleaseNULL(uvars->openProviders);
5543 }
5544
5545 ret = kIOReturnSuccess;
5546
5547 finish:
5548 IOLockUnlock(client->reserved->uvars->uvarsLock);
5549
5550 return ret;
5551 }
5552
5553
5554 IOReturn
serviceStop(IOService * service,IOService *)5555 IOUserServer::serviceStop(IOService * service, IOService *)
5556 {
5557 IOReturn ret;
5558 uint32_t idx, queueAlloc;
5559 bool pmAck;
5560 OSObjectUserVars * uvars;
5561 IODispatchQueue ** unboundedQueueArray = NULL;
5562 pmAck = false;
5563 IOLockLock(fLock);
5564 idx = fServices->getNextIndexOfObject(service, 0);
5565 if (-1U != idx) {
5566 fServices->removeObject(idx);
5567
5568 // Remove the service from IOAssociatedServices
5569 OSObject * serviceArrayObj = copyProperty(gIOAssociatedServicesKey);
5570 OSArray * serviceArray = OSDynamicCast(OSArray, serviceArrayObj);
5571 assert(serviceArray != NULL);
5572
5573 serviceArray = OSDynamicCast(OSArray, serviceArray->copyCollection());
5574 assert(serviceArray != NULL);
5575
5576 // Index should be the same as it was in fServices
5577 OSNumber * __assert_only registryEntryID = OSDynamicCast(OSNumber, serviceArray->getObject(idx));
5578 assert(registryEntryID);
5579
5580 // ensure it is the right service
5581 assert(registryEntryID->unsigned64BitValue() == service->getRegistryEntryID());
5582 serviceArray->removeObject(idx);
5583
5584 setProperty(gIOAssociatedServicesKey, serviceArray);
5585 OSSafeReleaseNULL(serviceArray);
5586 OSSafeReleaseNULL(serviceArrayObj);
5587
5588 uvars = service->reserved->uvars;
5589 uvars->stopped = true;
5590 uvars->powerState = 0;
5591
5592 bool allPowerStates __block = 0;
5593 // any service on?
5594 fServices->iterateObjects(^bool (OSObject * obj) {
5595 int service __unused; // hide outer defn
5596 IOService * nextService;
5597 nextService = (IOService *) obj;
5598 allPowerStates = nextService->reserved->uvars->powerState;
5599 // early terminate if true
5600 return allPowerStates;
5601 });
5602
5603 if (!allPowerStates && (pmAck = fSystemPowerAck)) {
5604 fSystemPowerAck = false;
5605 fSystemOff = true;
5606 }
5607 }
5608 IOLockUnlock(fLock);
5609 if (pmAck) {
5610 IOServicePH::serverAck(this);
5611 }
5612
5613 if (-1U == idx) {
5614 return kIOReturnSuccess;
5615 }
5616
5617 if (uvars->queueArray && uvars->userMeta) {
5618 queueAlloc = 1;
5619 if (uvars->userMeta->queueNames) {
5620 queueAlloc += uvars->userMeta->queueNames->count;
5621 }
5622 for (idx = 0; idx < queueAlloc; idx++) {
5623 OSSafeReleaseNULL(uvars->queueArray[idx]);
5624 }
5625 unboundedQueueArray = uvars->queueArray.data();
5626 IOSafeDeleteNULL(unboundedQueueArray, IODispatchQueue *, queueAlloc);
5627 uvars->queueArray = OSBoundedArrayRef<IODispatchQueue *>();
5628 }
5629
5630 (void) service->deRegisterInterestedDriver(this);
5631 if (uvars->userServerPM) {
5632 service->PMstop();
5633 }
5634
5635 ret = kIOReturnSuccess;
5636 return ret;
5637 }
5638
5639 void
serviceFree(IOService * service)5640 IOUserServer::serviceFree(IOService * service)
5641 {
5642 OSObjectUserVars * uvars;
5643
5644 uvars = service->reserved->uvars;
5645 if (!uvars) {
5646 return;
5647 }
5648 OSSafeReleaseNULL(uvars->userServer);
5649 IOLockFree(uvars->uvarsLock);
5650 IOFreeType(service->reserved->uvars, OSObjectUserVars);
5651 }
5652
5653 void
serviceWillTerminate(IOService * client,IOService * provider,IOOptionBits options)5654 IOUserServer::serviceWillTerminate(IOService * client, IOService * provider, IOOptionBits options)
5655 {
5656 IOReturn ret;
5657 bool willTerminate;
5658
5659 willTerminate = false;
5660 IOLockLock(client->reserved->uvars->uvarsLock);
5661 if (!client->reserved->uvars->serverDied
5662 && !client->reserved->uvars->willTerminate) {
5663 client->reserved->uvars->willTerminate = true;
5664 willTerminate = true;
5665 }
5666 IOLockUnlock(client->reserved->uvars->uvarsLock);
5667
5668 if (willTerminate) {
5669 if (provider->isInactive() || IOServicePH::serverSlept()) {
5670 client->Stop_async(provider);
5671 ret = kIOReturnOffline;
5672 } else {
5673 ret = client->Stop(provider);
5674 }
5675 if (kIOReturnSuccess != ret) {
5676 IOUserServer::serviceDidStop(client, provider);
5677 ret = kIOReturnSuccess;
5678 }
5679 }
5680 }
5681
5682 void
serviceDidTerminate(IOService * client,IOService * provider,IOOptionBits options,bool * defer)5683 IOUserServer::serviceDidTerminate(IOService * client, IOService * provider, IOOptionBits options, bool * defer)
5684 {
5685 IOLockLock(client->reserved->uvars->uvarsLock);
5686 client->reserved->uvars->didTerminate = true;
5687 if (!client->reserved->uvars->serverDied
5688 && !client->reserved->uvars->stopped) {
5689 *defer = true;
5690 }
5691 IOLockUnlock(client->reserved->uvars->uvarsLock);
5692 }
5693
5694 void
serviceDidStop(IOService * client,IOService * provider)5695 IOUserServer::serviceDidStop(IOService * client, IOService * provider)
5696 {
5697 bool complete;
5698 OSArray * closeArray;
5699
5700 complete = false;
5701 closeArray = NULL;
5702
5703 IOLockLock(client->reserved->uvars->uvarsLock);
5704 if (client->reserved->uvars
5705 && client->reserved->uvars->willTerminate
5706 && !client->reserved->uvars->stopped) {
5707 client->reserved->uvars->stopped = true;
5708 complete = client->reserved->uvars->didTerminate;
5709 }
5710
5711 if (client->reserved->uvars) {
5712 closeArray = client->reserved->uvars->openProviders;
5713 client->reserved->uvars->openProviders = NULL;
5714 }
5715 IOLockUnlock(client->reserved->uvars->uvarsLock);
5716
5717 if (closeArray) {
5718 closeArray->iterateObjects(^bool (OSObject * obj) {
5719 IOService * toClose;
5720 toClose = OSDynamicCast(IOService, obj);
5721 if (toClose) {
5722 DKLOG(DKS ":force close (" DKS ")\n", DKN(client), DKN(toClose));
5723 toClose->close(client);
5724 }
5725 return false;
5726 });
5727 closeArray->release();
5728 }
5729
5730 if (complete) {
5731 bool defer = false;
5732 client->didTerminate(provider, 0, &defer);
5733 }
5734 }
5735
5736 kern_return_t
ClientCrashed_Impl(IOService * client,uint64_t options)5737 IOService::ClientCrashed_Impl(
5738 IOService * client,
5739 uint64_t options)
5740 {
5741 return kIOReturnUnsupported;
5742 }
5743
5744 kern_return_t
Stop_Impl(IOService * provider)5745 IOService::Stop_Impl(
5746 IOService * provider)
5747 {
5748 IOUserServer::serviceDidStop(this, provider);
5749
5750 return kIOReturnSuccess;
5751 }
5752
5753 void
Stop_async_Impl(IOService * provider)5754 IOService::Stop_async_Impl(
5755 IOService * provider)
5756 {
5757 }
5758
5759 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5760
5761 #undef super
5762 #define super IOUserClient
5763
OSDefineMetaClassAndStructors(IOUserUserClient,IOUserClient)5764 OSDefineMetaClassAndStructors(IOUserUserClient, IOUserClient)
5765
5766 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5767
5768 bool
5769 IOUserUserClient::init(OSDictionary * properties)
5770 {
5771 if (!super::init(properties)) {
5772 return false;
5773 }
5774
5775 fWorkGroups = OSDictionary::withCapacity(0);
5776 if (fWorkGroups == NULL) {
5777 return false;
5778 }
5779
5780 fEventLinks = OSDictionary::withCapacity(0);
5781 if (fEventLinks == NULL) {
5782 return false;
5783 }
5784
5785 fLock = IOLockAlloc();
5786
5787 return true;
5788 }
5789
5790 void
free()5791 IOUserUserClient::free()
5792 {
5793 OSSafeReleaseNULL(fWorkGroups);
5794 OSSafeReleaseNULL(fEventLinks);
5795 if (fLock) {
5796 IOLockFree(fLock);
5797 }
5798
5799 super::free();
5800 }
5801
5802 IOReturn
setTask(task_t task)5803 IOUserUserClient::setTask(task_t task)
5804 {
5805 task_reference(task);
5806 fTask = task;
5807
5808 return kIOReturnSuccess;
5809 }
5810
5811 void
stop(IOService * provider)5812 IOUserUserClient::stop(IOService * provider)
5813 {
5814 if (fTask) {
5815 task_deallocate(fTask);
5816 fTask = NULL;
5817 }
5818 super::stop(provider);
5819 }
5820
5821 IOReturn
clientClose(void)5822 IOUserUserClient::clientClose(void)
5823 {
5824 terminate(kIOServiceTerminateNeedWillTerminate);
5825 return kIOReturnSuccess;
5826 }
5827
5828 IOReturn
setProperties(OSObject * properties)5829 IOUserUserClient::setProperties(OSObject * properties)
5830 {
5831 IOReturn ret = kIOReturnUnsupported;
5832 return ret;
5833 }
5834
5835 // p1 - name of object
5836 // p2 - length of object name
5837 // p3 - mach port name
5838
5839 kern_return_t
eventlinkConfigurationTrap(void * p1,void * p2,void * p3,void * p4,void * p5,void * p6)5840 IOUserUserClient::eventlinkConfigurationTrap(void * p1, void * p2, void * p3, void * p4, void * p5, void * p6)
5841 {
5842 user_addr_t userObjectName = (user_addr_t)p1;
5843 mach_port_name_t portName = (mach_port_name_t)(uintptr_t)p3;
5844 mach_port_t port = MACH_PORT_NULL;
5845 ipc_kobject_type_t portType;
5846 char eventlinkName[kIOEventLinkMaxNameLength + 1] = {0};
5847 size_t eventLinkNameLen;
5848 OSString * eventlinkNameStr = NULL; // must release
5849 IOEventLink * eventLink = NULL; // do not release
5850 kern_return_t ret;
5851
5852 ret = copyinstr(userObjectName, &eventlinkName[0], sizeof(eventlinkName), &eventLinkNameLen);
5853 if (ret != kIOReturnSuccess) {
5854 goto finish;
5855 }
5856
5857 // ensure string length matches trap argument
5858 if (eventLinkNameLen != (size_t)p2 + 1) {
5859 ret = kIOReturnBadArgument;
5860 goto finish;
5861 }
5862
5863 eventlinkNameStr = OSString::withCStringNoCopy(eventlinkName);
5864 if (eventlinkNameStr == NULL) {
5865 ret = kIOReturnNoMemory;
5866 goto finish;
5867 }
5868
5869 IOLockLock(fLock);
5870 eventLink = OSDynamicCast(IOEventLink, fEventLinks->getObject(eventlinkNameStr));
5871 if (eventLink) {
5872 eventLink->retain();
5873 }
5874 IOLockUnlock(fLock);
5875
5876 if (eventLink == NULL) {
5877 ret = kIOReturnNotFound;
5878 goto finish;
5879 }
5880
5881 port = iokit_lookup_raw_current_task(portName, &portType);
5882
5883 if (port == NULL) {
5884 ret = kIOReturnNotFound;
5885 goto finish;
5886 }
5887
5888 if (portType != IKOT_EVENTLINK) {
5889 ret = kIOReturnBadArgument;
5890 goto finish;
5891 }
5892
5893 ret = eventLink->SetEventlinkPort(port);
5894 if (ret != kIOReturnSuccess) {
5895 if (kIODKLogSetup & gIODKDebug) {
5896 DKLOG(DKS " %s SetEventlinkPort() returned %x\n", DKN(this), eventlinkNameStr->getCStringNoCopy(), ret);
5897 }
5898 goto finish;
5899 }
5900
5901 finish:
5902 if (port != NULL) {
5903 iokit_release_port_send(port);
5904 }
5905
5906 OSSafeReleaseNULL(eventlinkNameStr);
5907 OSSafeReleaseNULL(eventLink);
5908
5909 return ret;
5910 }
5911
5912 kern_return_t
workgroupConfigurationTrap(void * p1,void * p2,void * p3,void * p4,void * p5,void * p6)5913 IOUserUserClient::workgroupConfigurationTrap(void * p1, void * p2, void * p3, void * p4, void * p5, void * p6)
5914 {
5915 user_addr_t userObjectName = (user_addr_t)p1;
5916 mach_port_name_t portName = (mach_port_name_t)(uintptr_t)p3;
5917 mach_port_t port = MACH_PORT_NULL;
5918 ipc_kobject_type_t portType;
5919 char workgroupName[kIOWorkGroupMaxNameLength + 1] = {0};
5920 size_t workgroupNameLen;
5921 OSString * workgroupNameStr = NULL; // must release
5922 IOWorkGroup * workgroup = NULL; // do not release
5923 kern_return_t ret;
5924
5925 ret = copyinstr(userObjectName, &workgroupName[0], sizeof(workgroupName), &workgroupNameLen);
5926 if (ret != kIOReturnSuccess) {
5927 goto finish;
5928 }
5929
5930 // ensure string length matches trap argument
5931 if (workgroupNameLen != (size_t)p2 + 1) {
5932 ret = kIOReturnBadArgument;
5933 goto finish;
5934 }
5935
5936 workgroupNameStr = OSString::withCStringNoCopy(workgroupName);
5937 if (workgroupNameStr == NULL) {
5938 ret = kIOReturnNoMemory;
5939 goto finish;
5940 }
5941
5942 IOLockLock(fLock);
5943 workgroup = OSDynamicCast(IOWorkGroup, fWorkGroups->getObject(workgroupNameStr));
5944 if (workgroup) {
5945 workgroup->retain();
5946 }
5947 IOLockUnlock(fLock);
5948
5949 if (workgroup == NULL) {
5950 ret = kIOReturnNotFound;
5951 goto finish;
5952 }
5953
5954 port = iokit_lookup_raw_current_task(portName, &portType);
5955
5956 if (port == NULL) {
5957 ret = kIOReturnNotFound;
5958 goto finish;
5959 }
5960
5961 if (portType != IKOT_WORK_INTERVAL) {
5962 ret = kIOReturnBadArgument;
5963 goto finish;
5964 }
5965
5966 ret = workgroup->SetWorkGroupPort(port);
5967 if (ret != kIOReturnSuccess) {
5968 if (kIODKLogSetup & gIODKDebug) {
5969 DKLOG(DKS " %s SetWorkGroupPort() returned %x\n", DKN(this), workgroupNameStr->getCStringNoCopy(), ret);
5970 }
5971 goto finish;
5972 }
5973
5974 finish:
5975
5976 if (port != NULL) {
5977 iokit_release_port_send(port);
5978 }
5979
5980 OSSafeReleaseNULL(workgroupNameStr);
5981 OSSafeReleaseNULL(workgroup);
5982
5983 return ret;
5984 }
5985
5986 IOExternalTrap *
getTargetAndTrapForIndex(IOService ** targetP,UInt32 index)5987 IOUserUserClient::getTargetAndTrapForIndex( IOService **targetP, UInt32 index )
5988 {
5989 static const OSBoundedArray<IOExternalTrap, 2> trapTemplate = {{
5990 { NULL, (IOTrap) & IOUserUserClient::eventlinkConfigurationTrap},
5991 { NULL, (IOTrap) & IOUserUserClient::workgroupConfigurationTrap},
5992 }};
5993 if (index >= trapTemplate.size()) {
5994 return NULL;
5995 }
5996 *targetP = this;
5997 return (IOExternalTrap *)&trapTemplate[index];
5998 }
5999
6000 kern_return_t
CopyClientEntitlements_Impl(OSDictionary ** entitlements)6001 IOUserClient::CopyClientEntitlements_Impl(OSDictionary ** entitlements)
6002 {
6003 return kIOReturnUnsupported;
6004 };
6005
6006 struct IOUserUserClientActionRef {
6007 OSAsyncReference64 asyncRef;
6008 };
6009
6010 void
KernelCompletion_Impl(OSAction * action,IOReturn status,const unsigned long long * asyncData,uint32_t asyncDataCount)6011 IOUserClient::KernelCompletion_Impl(
6012 OSAction * action,
6013 IOReturn status,
6014 const unsigned long long * asyncData,
6015 uint32_t asyncDataCount)
6016 {
6017 IOUserUserClientActionRef * ref;
6018
6019 ref = (typeof(ref))action->GetReference();
6020
6021 IOUserClient::sendAsyncResult64(ref->asyncRef, status, (io_user_reference_t *) asyncData, asyncDataCount);
6022 }
6023
6024 kern_return_t
_ExternalMethod_Impl(uint64_t selector,const unsigned long long * scalarInput,uint32_t scalarInputCount,OSData * structureInput,IOMemoryDescriptor * structureInputDescriptor,unsigned long long * scalarOutput,uint32_t * scalarOutputCount,uint64_t structureOutputMaximumSize,OSData ** structureOutput,IOMemoryDescriptor * structureOutputDescriptor,OSAction * completion)6025 IOUserClient::_ExternalMethod_Impl(
6026 uint64_t selector,
6027 const unsigned long long * scalarInput,
6028 uint32_t scalarInputCount,
6029 OSData * structureInput,
6030 IOMemoryDescriptor * structureInputDescriptor,
6031 unsigned long long * scalarOutput,
6032 uint32_t * scalarOutputCount,
6033 uint64_t structureOutputMaximumSize,
6034 OSData ** structureOutput,
6035 IOMemoryDescriptor * structureOutputDescriptor,
6036 OSAction * completion)
6037 {
6038 return kIOReturnUnsupported;
6039 }
6040
6041 IOReturn
clientMemoryForType(UInt32 type,IOOptionBits * koptions,IOMemoryDescriptor ** kmemory)6042 IOUserUserClient::clientMemoryForType(UInt32 type,
6043 IOOptionBits * koptions,
6044 IOMemoryDescriptor ** kmemory)
6045 {
6046 IOReturn kr;
6047 uint64_t options;
6048 IOMemoryDescriptor * memory;
6049
6050 kr = CopyClientMemoryForType(type, &options, &memory);
6051
6052 *koptions = 0;
6053 *kmemory = NULL;
6054 if (kIOReturnSuccess != kr) {
6055 return kr;
6056 }
6057
6058 if (kIOUserClientMemoryReadOnly & options) {
6059 *koptions |= kIOMapReadOnly;
6060 }
6061 *kmemory = memory;
6062
6063 return kr;
6064 }
6065
6066 IOReturn
externalMethod(uint32_t selector,IOExternalMethodArguments * args,IOExternalMethodDispatch * dispatch,OSObject * target,void * reference)6067 IOUserUserClient::externalMethod(uint32_t selector, IOExternalMethodArguments * args,
6068 IOExternalMethodDispatch * dispatch, OSObject * target, void * reference)
6069 {
6070 IOReturn kr;
6071 OSData * structureInput;
6072 OSData * structureOutput;
6073 size_t copylen;
6074 uint64_t structureOutputSize;
6075 OSAction * action;
6076 IOUserUserClientActionRef * ref;
6077 mach_port_t wake_port = MACH_PORT_NULL;
6078
6079 kr = kIOReturnUnsupported;
6080 structureInput = NULL;
6081 action = NULL;
6082 ref = NULL;
6083
6084 if (args->structureInputSize) {
6085 structureInput = OSData::withBytesNoCopy((void *) args->structureInput, args->structureInputSize);
6086 }
6087
6088 if (MACH_PORT_NULL != args->asyncWakePort) {
6089 // this retain is for the OSAction to release
6090 wake_port = ipc_port_make_send_mqueue(args->asyncWakePort);
6091 kr = CreateActionKernelCompletion(sizeof(IOUserUserClientActionRef), &action);
6092 assert(KERN_SUCCESS == kr);
6093 ref = (typeof(ref))action->GetReference();
6094 bcopy(args->asyncReference, &ref->asyncRef[0], args->asyncReferenceCount * sizeof(ref->asyncRef[0]));
6095 kr = action->SetAbortedHandler(^(void) {
6096 IOUserUserClientActionRef * ref;
6097 IOReturn ret;
6098
6099 ref = (typeof(ref))action->GetReference();
6100 ret = releaseAsyncReference64(ref->asyncRef);
6101 assert(kIOReturnSuccess == ret);
6102 bzero(&ref->asyncRef[0], sizeof(ref->asyncRef));
6103 });
6104 assert(KERN_SUCCESS == kr);
6105 }
6106
6107 if (args->structureVariableOutputData) {
6108 structureOutputSize = kIOUserClientVariableStructureSize;
6109 } else if (args->structureOutputDescriptor) {
6110 structureOutputSize = args->structureOutputDescriptor->getLength();
6111 } else {
6112 structureOutputSize = args->structureOutputSize;
6113 }
6114
6115 kr = _ExternalMethod(selector, &args->scalarInput[0], args->scalarInputCount,
6116 structureInput, args->structureInputDescriptor,
6117 args->scalarOutput, &args->scalarOutputCount,
6118 structureOutputSize, &structureOutput, args->structureOutputDescriptor,
6119 action);
6120
6121 OSSafeReleaseNULL(structureInput);
6122 OSSafeReleaseNULL(action);
6123
6124 if (kr == kIOReturnSuccess && structureOutput) {
6125 if (args->structureVariableOutputData) {
6126 *args->structureVariableOutputData = structureOutput;
6127 } else {
6128 copylen = structureOutput->getLength();
6129 if (copylen > args->structureOutputSize) {
6130 kr = kIOReturnBadArgument;
6131 } else {
6132 bcopy((const void *) structureOutput->getBytesNoCopy(), args->structureOutput, copylen);
6133 args->structureOutputSize = (uint32_t) copylen;
6134 }
6135 OSSafeReleaseNULL(structureOutput);
6136 }
6137 }
6138
6139 if (kIOReturnSuccess != kr) {
6140 // mig will destroy any async port
6141 return kr;
6142 }
6143
6144 // We must never return error after this point in order to preserve MIG ownership semantics
6145 assert(kr == kIOReturnSuccess);
6146 if (MACH_PORT_NULL != wake_port) {
6147 // this release is for the mig created send right
6148 iokit_release_port_send(wake_port);
6149 }
6150
6151 return kr;
6152 }
6153
6154 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6155
6156 extern IORecursiveLock * gDriverKitLaunchLock;
6157 extern OSSet * gDriverKitLaunches;
6158
6159 _IOUserServerCheckInCancellationHandler *
setCancellationHandler(IOUserServerCheckInCancellationHandler handler,void * handlerArgs)6160 IOUserServerCheckInToken::setCancellationHandler(IOUserServerCheckInCancellationHandler handler,
6161 void* handlerArgs)
6162 {
6163 _IOUserServerCheckInCancellationHandler * handlerObj = _IOUserServerCheckInCancellationHandler::withHandler(handler, handlerArgs);
6164 if (!handlerObj) {
6165 goto finish;
6166 }
6167
6168 IORecursiveLockLock(gDriverKitLaunchLock);
6169
6170 assert(fState != kIOUserServerCheckInComplete);
6171
6172 if (fState == kIOUserServerCheckInCanceled) {
6173 // Send cancel notification if we set the handler after this was canceled
6174 handlerObj->call(this);
6175 } else if (fState == kIOUserServerCheckInPending) {
6176 fHandlers->setObject(handlerObj);
6177 }
6178
6179 IORecursiveLockUnlock(gDriverKitLaunchLock);
6180
6181 finish:
6182 return handlerObj;
6183 }
6184
6185 void
removeCancellationHandler(_IOUserServerCheckInCancellationHandler * handler)6186 IOUserServerCheckInToken::removeCancellationHandler(_IOUserServerCheckInCancellationHandler * handler)
6187 {
6188 IORecursiveLockLock(gDriverKitLaunchLock);
6189
6190 fHandlers->removeObject(handler);
6191
6192 IORecursiveLockUnlock(gDriverKitLaunchLock);
6193 }
6194
6195 void
cancel()6196 IOUserServerCheckInToken::cancel()
6197 {
6198 IORecursiveLockLock(gDriverKitLaunchLock);
6199
6200 if (fState == kIOUserServerCheckInPending) {
6201 fState = kIOUserServerCheckInCanceled;
6202 if (gDriverKitLaunches != NULL) {
6203 // Remove pending launch from list, if we have not shut down yet.
6204 gDriverKitLaunches->removeObject(this);
6205 }
6206
6207 fHandlers->iterateObjects(^bool (OSObject * obj){
6208 _IOUserServerCheckInCancellationHandler * handlerObj = OSDynamicCast(_IOUserServerCheckInCancellationHandler, obj);
6209 if (handlerObj) {
6210 handlerObj->call(this);
6211 }
6212 return false;
6213 });
6214 fHandlers->flushCollection();
6215 }
6216
6217 IORecursiveLockUnlock(gDriverKitLaunchLock);
6218 }
6219
6220 void
complete()6221 IOUserServerCheckInToken::complete()
6222 {
6223 IORecursiveLockLock(gDriverKitLaunchLock);
6224
6225 if (fState == kIOUserServerCheckInPending && --fPendingCount == 0) {
6226 fState = kIOUserServerCheckInComplete;
6227 if (gDriverKitLaunches != NULL) {
6228 // Remove pending launch from list, if we have not shut down yet.
6229 gDriverKitLaunches->removeObject(this);
6230 }
6231
6232 // No need to hold on to the cancellation handlers
6233 fHandlers->flushCollection();
6234 }
6235
6236 IORecursiveLockUnlock(gDriverKitLaunchLock);
6237 }
6238
6239 bool
init(const OSSymbol * serverName,OSNumber * serverTag,OSKext * driverKext,OSData * serverDUI)6240 IOUserServerCheckInToken::init(const OSSymbol * serverName, OSNumber * serverTag, OSKext *driverKext, OSData *serverDUI)
6241 {
6242 if (!OSObject::init()) {
6243 return false;
6244 }
6245
6246 if (!serverName) {
6247 return false;
6248 }
6249 fServerName = serverName;
6250 fServerName->retain();
6251
6252 if (!serverTag) {
6253 return false;
6254 }
6255 fServerTag = serverTag;
6256 fServerTag->retain();
6257
6258 fHandlers = OSSet::withCapacity(0);
6259 if (!fHandlers) {
6260 return false;
6261 }
6262
6263 fState = kIOUserServerCheckInPending;
6264 fPendingCount = 1;
6265
6266 fKextBundleID = NULL;
6267 fNeedDextDec = false;
6268
6269 fExecutableName = NULL;
6270
6271 if (driverKext) {
6272 fExecutableName = OSDynamicCast(OSSymbol, driverKext->getBundleExecutable());
6273
6274 if (fExecutableName) {
6275 fExecutableName->retain();
6276 }
6277
6278 /*
6279 * We need to keep track of how many dexts we have started.
6280 * For every new dext we are going to create a new token, and
6281 * we consider the token creation as the initial step to
6282 * create a dext as it is the data structure that will back up
6283 * the userspace dance to start a dext.
6284 * We later have to decrement only once per token.
6285 * If no error occurs we consider the finalize() call on IOUserServer
6286 * as the moment in which we do not consider the dext "alive" anymore;
6287 * however in case of errors we will still need to decrement the count
6288 * otherwise upgrades of the dext will never make progress.
6289 */
6290 if (OSKext::incrementDextLaunchCount(driverKext, serverDUI)) {
6291 /*
6292 * If fKext holds a pointer,
6293 * it is the indication that a decrements needs
6294 * to be called.
6295 */
6296 fNeedDextDec = true;
6297 fKextBundleID = OSDynamicCast(OSString, driverKext->getIdentifier());
6298 fKextBundleID->retain();
6299 } else {
6300 return false;
6301 }
6302 }
6303
6304 return true;
6305 }
6306
6307 /*
6308 * Returns if the dext can be re-used
6309 * for matching.
6310 */
6311 bool
dextTerminate(void)6312 IOUserServerCheckInToken::dextTerminate(void)
6313 {
6314 bool ret = true;
6315
6316 if (fNeedDextDec == true) {
6317 /*
6318 * We can decrement DextLaunchCount only
6319 * once per token.
6320 */
6321 ret = !(OSKext::decrementDextLaunchCount(fKextBundleID));
6322 fNeedDextDec = false;
6323 }
6324
6325 return ret;
6326 }
6327
6328 void
free()6329 IOUserServerCheckInToken::free()
6330 {
6331 OSSafeReleaseNULL(fServerName);
6332 OSSafeReleaseNULL(fServerTag);
6333 OSSafeReleaseNULL(fExecutableName);
6334 OSSafeReleaseNULL(fHandlers);
6335 if (fKextBundleID != NULL) {
6336 dextTerminate();
6337 OSSafeReleaseNULL(fKextBundleID);
6338 }
6339
6340 OSObject::free();
6341 }
6342
6343 const OSSymbol *
copyServerName() const6344 IOUserServerCheckInToken::copyServerName() const
6345 {
6346 fServerName->retain();
6347 return fServerName;
6348 }
6349
6350 OSNumber *
copyServerTag() const6351 IOUserServerCheckInToken::copyServerTag() const
6352 {
6353 fServerTag->retain();
6354 return fServerTag;
6355 }
6356
6357 IOUserServer *
launchUserServer(OSString * bundleID,const OSSymbol * serverName,OSNumber * serverTag,bool reuseIfExists,IOUserServerCheckInToken ** resultToken,OSData * serverDUI)6358 IOUserServer::launchUserServer(OSString * bundleID, const OSSymbol * serverName, OSNumber * serverTag, bool reuseIfExists, IOUserServerCheckInToken ** resultToken, OSData *serverDUI)
6359 {
6360 IOUserServer *me = NULL;
6361 IOUserServerCheckInToken * token = NULL;
6362 OSDictionary * matching = NULL; // must release
6363 OSKext * driverKext = NULL; // must release
6364 OSDextStatistics * driverStatistics = NULL; // must release
6365 bool reslide = false;
6366
6367 /* TODO: Check we are looking for same dextID
6368 * and if it is not the same
6369 * restart the matching process.
6370 */
6371 driverKext = OSKext::lookupDextWithIdentifier(bundleID, serverDUI);
6372 if (driverKext != NULL) {
6373 driverStatistics = driverKext->copyDextStatistics();
6374 if (driverStatistics == NULL) {
6375 panic("Kext %s was not a DriverKit OSKext", bundleID->getCStringNoCopy());
6376 }
6377 IOLog("Driver %s has crashed %zu time(s)\n", bundleID->getCStringNoCopy(), driverStatistics->getCrashCount());
6378 reslide = driverStatistics->getCrashCount() > 0;
6379 } else {
6380 DKLOG("Could not find OSKext for %s\n", bundleID->getCStringNoCopy());
6381 *resultToken = NULL;
6382 return NULL;
6383 }
6384
6385 IORecursiveLockLock(gDriverKitLaunchLock);
6386
6387 if (gDriverKitLaunches == NULL) {
6388 // About to shut down, don't launch anything
6389 goto finish;
6390 }
6391
6392 if (reuseIfExists) {
6393 const char * serverNameCStr;
6394 const char * bundleIDCStr;
6395 const char * endOrgCStr;
6396
6397 serverNameCStr = serverName->getCStringNoCopy();
6398 bundleIDCStr = bundleID->getCStringNoCopy();
6399 (endOrgCStr = strchr(bundleIDCStr, '.')) && (endOrgCStr = strchr(endOrgCStr + 1, '.'));
6400 reuseIfExists = endOrgCStr && (0 == strncmp(bundleIDCStr, serverNameCStr, endOrgCStr + 1 - bundleIDCStr));
6401 if (!reuseIfExists) {
6402 IOLog(kIOUserServerNameKey " \"%s\" not correct organization for bundleID \"%s\"\n", serverNameCStr, bundleIDCStr);
6403 }
6404 }
6405
6406 // Find existing server
6407 if (reuseIfExists) {
6408 token = IOUserServerCheckInToken::findExistingToken(serverName);
6409 if (token) {
6410 // Launch in progress, return token
6411 goto finish;
6412 } else {
6413 // Check if launch completed
6414 matching = IOService::serviceMatching(gIOUserServerClassKey);
6415 if (!matching) {
6416 goto finish;
6417 }
6418 IOService::propertyMatching(gIOUserServerNameKey, serverName, matching);
6419 IOService * service = IOService::copyMatchingService(matching);
6420 IOUserServer * userServer = OSDynamicCast(IOUserServer, service);
6421 if (userServer) {
6422 // found existing user server
6423 me = userServer;
6424 goto finish;
6425 } else {
6426 OSSafeReleaseNULL(service);
6427 }
6428 }
6429 }
6430
6431 // No existing server, request launch
6432 token = new IOUserServerCheckInToken;
6433 if (!token) {
6434 goto finish;
6435 }
6436
6437 /*
6438 * TODO: If the init fails because the personalities are not up to date
6439 * restart the whole matching process.
6440 */
6441 if (token && !token->init(serverName, serverTag, driverKext, serverDUI)) {
6442 IOLog("Could not initialize token\n");
6443 OSSafeReleaseNULL(token);
6444 goto finish;
6445 }
6446
6447 /*
6448 * If the launch fails at any point terminate() will
6449 * be called on this IOUserServer.
6450 */
6451 gDriverKitLaunches->setObject(token);
6452 OSKext::requestDaemonLaunch(bundleID, (OSString *)serverName, serverTag, reslide ? kOSBooleanTrue : kOSBooleanFalse, token, serverDUI);
6453
6454 finish:
6455 IORecursiveLockUnlock(gDriverKitLaunchLock);
6456 OSSafeReleaseNULL(matching);
6457 OSSafeReleaseNULL(driverStatistics);
6458 OSSafeReleaseNULL(driverKext);
6459
6460 if (resultToken) {
6461 *resultToken = token;
6462 } else {
6463 OSSafeReleaseNULL(token);
6464 }
6465
6466 return me;
6467 }
6468
6469 /*
6470 * IOUserServerCheckInTokens are used to track dext launches. They have three possible states:
6471 *
6472 * - Pending: A dext launch is pending
6473 * - Canceled: Dext launch failed
6474 * - Complete: Dext launch is complete
6475 *
6476 * A token can be shared among multiple IOServices that are waiting for dexts if the IOUserServerName
6477 * is the same. This allows dexts to be reused and host multiple services. All pending tokens are stored
6478 * in gDriverKitLaunches and we check here before creating a new token when launching a dext.
6479 *
6480 * A token starts in the pending state with a pending count of 1. When we reuse a token, we increase the
6481 * pending count of the token.
6482 *
6483 * The token is sent to userspace as a mach port through kernelmanagerd/driverkitd to the dext. The dext then
6484 * uses that token to check in to the kernel. If any part of the dext launch failed (dext crashed, kmd crashed, etc.)
6485 * we get a no-senders notification for the token in the kernel and the token goes into the Canceled state.
6486 *
6487 * Once the dext checks in to the kernel, we decrement the pending count for the token. When the pending count reaches
6488 * 0, the token goes into the Complete state. So if the token is in the Complete state, there are no kernel matching threads
6489 * waiting on the dext to check in.
6490 */
6491
6492 IOUserServerCheckInToken *
findExistingToken(const OSSymbol * serverName)6493 IOUserServerCheckInToken::findExistingToken(const OSSymbol * serverName)
6494 {
6495 IOUserServerCheckInToken * __block result = NULL;
6496
6497 IORecursiveLockLock(gDriverKitLaunchLock);
6498 if (gDriverKitLaunches == NULL) {
6499 goto finish;
6500 }
6501
6502 gDriverKitLaunches->iterateObjects(^(OSObject * obj) {
6503 IOUserServerCheckInToken * token = OSDynamicCast(IOUserServerCheckInToken, obj);
6504 if (token) {
6505 // Check if server name matches
6506 const OSSymbol * tokenServerName = token->fServerName;
6507 if (tokenServerName->isEqualTo(serverName)) {
6508 assert(token->fState == kIOUserServerCheckInPending);
6509 token->fPendingCount++;
6510 result = token;
6511 result->retain();
6512 }
6513 }
6514 return result != NULL;
6515 });
6516
6517 finish:
6518 IORecursiveLockUnlock(gDriverKitLaunchLock);
6519 return result;
6520 }
6521
6522 void
cancelAll()6523 IOUserServerCheckInToken::cancelAll()
6524 {
6525 OSSet * tokensToCancel;
6526
6527 IORecursiveLockLock(gDriverKitLaunchLock);
6528 tokensToCancel = gDriverKitLaunches;
6529 gDriverKitLaunches = NULL;
6530
6531
6532 tokensToCancel->iterateObjects(^(OSObject *obj) {
6533 IOUserServerCheckInToken * token = OSDynamicCast(IOUserServerCheckInToken, obj);
6534 if (token) {
6535 token->cancel();
6536 }
6537 return false;
6538 });
6539
6540 IORecursiveLockUnlock(gDriverKitLaunchLock);
6541
6542 OSSafeReleaseNULL(tokensToCancel);
6543 }
6544
6545 void
call(IOUserServerCheckInToken * token)6546 _IOUserServerCheckInCancellationHandler::call(IOUserServerCheckInToken * token)
6547 {
6548 fHandler(token, fHandlerArgs);
6549 }
6550
6551 _IOUserServerCheckInCancellationHandler *
withHandler(IOUserServerCheckInCancellationHandler handler,void * args)6552 _IOUserServerCheckInCancellationHandler::withHandler(IOUserServerCheckInCancellationHandler handler, void * args)
6553 {
6554 _IOUserServerCheckInCancellationHandler * handlerObj = NULL;
6555 if (!handler) {
6556 goto finish;
6557 }
6558
6559 handlerObj = new _IOUserServerCheckInCancellationHandler;
6560 if (!handlerObj) {
6561 goto finish;
6562 }
6563
6564 handlerObj->fHandler = handler;
6565 handlerObj->fHandlerArgs = args;
6566
6567 finish:
6568 return handlerObj;
6569 }
6570
6571 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6572
6573 struct IOServiceStateNotificationDispatchSource_IVars {
6574 IOLock * fLock;
6575 IOService * fStateNotification;
6576 IOStateNotificationListenerRef fListener;
6577 OSAction * fAction;
6578 bool fEnable;
6579 bool fArmed;
6580 };
6581
6582 kern_return_t
Create_Impl(IOService * service,OSArray * items,IODispatchQueue * queue,IOServiceStateNotificationDispatchSource ** outSource)6583 IOServiceStateNotificationDispatchSource::Create_Impl(IOService * service, OSArray * items,
6584 IODispatchQueue * queue, IOServiceStateNotificationDispatchSource ** outSource)
6585 {
6586 kern_return_t kr;
6587 IOServiceStateNotificationDispatchSource * source;
6588
6589 source = OSTypeAlloc(IOServiceStateNotificationDispatchSource);
6590 source->init();
6591
6592 source->ivars->fStateNotification = service;
6593 kr = service->stateNotificationListenerAdd(items, &source->ivars->fListener, ^kern_return_t () {
6594 OSAction * action;
6595
6596 action = NULL;
6597 IOLockLock(source->ivars->fLock);
6598 if (source->ivars->fArmed && source->ivars->fAction) {
6599 source->ivars->fArmed = false;
6600 action = source->ivars->fAction;
6601 action->retain();
6602 }
6603 IOLockUnlock(source->ivars->fLock);
6604 if (action) {
6605 source->StateNotificationReady(action);
6606 OSSafeReleaseNULL(action);
6607 }
6608 return kIOReturnSuccess;
6609 });
6610
6611 if (kIOReturnSuccess != kr) {
6612 OSSafeReleaseNULL(source);
6613 }
6614 *outSource = source;
6615
6616 return kr;
6617 }
6618
6619
6620 bool
init()6621 IOServiceStateNotificationDispatchSource::init()
6622 {
6623 if (!IODispatchSource::init()) {
6624 return false;
6625 }
6626 ivars = IOMallocType(IOServiceStateNotificationDispatchSource_IVars);
6627 if (!ivars) {
6628 return false;
6629 }
6630 ivars->fLock = IOLockAlloc();
6631 if (!ivars->fLock) {
6632 return false;
6633 }
6634 ivars->fArmed = true;
6635
6636 return true;
6637 }
6638
6639 void
free()6640 IOServiceStateNotificationDispatchSource::free()
6641 {
6642 if (ivars) {
6643 if (ivars->fListener) {
6644 ivars->fStateNotification->stateNotificationListenerRemove(ivars->fListener);
6645 }
6646 if (ivars->fLock) {
6647 IOLockFree(ivars->fLock);
6648 }
6649 IOFreeType(ivars, IOServiceStateNotificationDispatchSource_IVars);
6650 }
6651 IODispatchSource::free();
6652 }
6653
6654 kern_return_t
SetHandler_Impl(OSAction * action)6655 IOServiceStateNotificationDispatchSource::SetHandler_Impl(OSAction * action)
6656 {
6657 IOReturn ret;
6658 bool notifyReady;
6659
6660 notifyReady = false;
6661
6662 IOLockLock(ivars->fLock);
6663 action->retain();
6664 OSSafeReleaseNULL(ivars->fAction);
6665 ivars->fAction = action;
6666 if (action) {
6667 notifyReady = true;
6668 }
6669 IOLockUnlock(ivars->fLock);
6670
6671 if (notifyReady) {
6672 StateNotificationReady(action);
6673 }
6674 ret = kIOReturnSuccess;
6675
6676 return ret;
6677 }
6678
6679 kern_return_t
SetEnableWithCompletion_Impl(bool enable,IODispatchSourceCancelHandler handler)6680 IOServiceStateNotificationDispatchSource::SetEnableWithCompletion_Impl(
6681 bool enable,
6682 IODispatchSourceCancelHandler handler)
6683 {
6684 if (enable == ivars->fEnable) {
6685 return kIOReturnSuccess;
6686 }
6687
6688 IOLockLock(ivars->fLock);
6689 ivars->fEnable = enable;
6690 IOLockUnlock(ivars->fLock);
6691
6692 return kIOReturnSuccess;
6693 }
6694
6695 kern_return_t
Cancel_Impl(IODispatchSourceCancelHandler handler)6696 IOServiceStateNotificationDispatchSource::Cancel_Impl(
6697 IODispatchSourceCancelHandler handler)
6698 {
6699 return kIOReturnUnsupported;
6700 }
6701
6702 kern_return_t
StateNotificationBegin_Impl(void)6703 IOServiceStateNotificationDispatchSource::StateNotificationBegin_Impl(void)
6704 {
6705 IOLockLock(ivars->fLock);
6706 ivars->fArmed = true;
6707 IOLockUnlock(ivars->fLock);
6708
6709 return kIOReturnSuccess;
6710 }
6711
6712 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6713
6714 #include <IOKit/IOServiceStateNotificationEventSource.h>
6715
6716 OSDefineMetaClassAndStructors(IOServiceStateNotificationEventSource, IOEventSource)
6717 OSMetaClassDefineReservedUnused(IOServiceStateNotificationEventSource, 0);
6718 OSMetaClassDefineReservedUnused(IOServiceStateNotificationEventSource, 1);
6719 OSMetaClassDefineReservedUnused(IOServiceStateNotificationEventSource, 2);
6720 OSMetaClassDefineReservedUnused(IOServiceStateNotificationEventSource, 3);
6721 OSMetaClassDefineReservedUnused(IOServiceStateNotificationEventSource, 4);
6722 OSMetaClassDefineReservedUnused(IOServiceStateNotificationEventSource, 5);
6723 OSMetaClassDefineReservedUnused(IOServiceStateNotificationEventSource, 6);
6724 OSMetaClassDefineReservedUnused(IOServiceStateNotificationEventSource, 7);
6725
6726 OSPtr<IOServiceStateNotificationEventSource>
serviceStateNotificationEventSource(IOService * service,OSArray * items,ActionBlock inAction)6727 IOServiceStateNotificationEventSource::serviceStateNotificationEventSource(IOService *service,
6728 OSArray * items,
6729 ActionBlock inAction)
6730 {
6731 kern_return_t kr;
6732 IOServiceStateNotificationEventSource * source;
6733
6734 source = OSTypeAlloc(IOServiceStateNotificationEventSource);
6735 if (source && !source->init(service, NULL)) {
6736 OSSafeReleaseNULL(source);
6737 }
6738
6739 if (!source) {
6740 return nullptr;
6741 }
6742
6743 source->fStateNotification = service;
6744 kr = service->stateNotificationListenerAdd(items, &source->fListener, ^kern_return_t () {
6745 if (!source->workLoop) {
6746 return kIOReturnSuccess;
6747 }
6748 source->workLoop->runActionBlock(^IOReturn (void) {
6749 source->fArmed = true;
6750 return kIOReturnSuccess;
6751 });
6752 source->signalWorkAvailable();
6753 return kIOReturnSuccess;
6754 });
6755
6756 if (kIOReturnSuccess != kr) {
6757 OSSafeReleaseNULL(source);
6758 }
6759
6760 if (source) {
6761 source->setActionBlock((IOEventSource::ActionBlock) inAction);
6762 }
6763
6764 return source;
6765 }
6766
6767 void
free()6768 IOServiceStateNotificationEventSource::free()
6769 {
6770 if (fListener) {
6771 fStateNotification->stateNotificationListenerRemove(fListener);
6772 }
6773 IOEventSource::free();
6774 }
6775
6776 void
enable()6777 IOServiceStateNotificationEventSource::enable()
6778 {
6779 fEnable = true;
6780 }
6781
6782 void
disable()6783 IOServiceStateNotificationEventSource::disable()
6784 {
6785 fEnable = false;
6786 }
6787
6788 void
setWorkLoop(IOWorkLoop * inWorkLoop)6789 IOServiceStateNotificationEventSource::setWorkLoop(IOWorkLoop *inWorkLoop)
6790 {
6791 IOEventSource::setWorkLoop(inWorkLoop);
6792 }
6793
6794 bool
checkForWork()6795 IOServiceStateNotificationEventSource::checkForWork()
6796 {
6797 ActionBlock intActionBlock = (ActionBlock) actionBlock;
6798
6799 if (fArmed) {
6800 fArmed = false;
6801 (intActionBlock)();
6802 }
6803
6804 return false;
6805 }
6806
6807 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6808
6809 OSDefineMetaClassAndStructors(IOSystemStateNotification, IOService);
6810
6811 class IOStateNotificationItem : public OSObject
6812 {
6813 OSDeclareDefaultStructors(IOStateNotificationItem);
6814
6815 public:
6816 virtual bool init() override;
6817
6818 OSDictionary * fSchema;
6819 OSDictionary * fValue;
6820 OSSet * fListeners;
6821 };
6822 OSDefineMetaClassAndStructors(IOStateNotificationItem, OSObject);
6823
6824
6825 class IOStateNotificationListener : public OSObject
6826 {
6827 OSDeclareDefaultStructors(IOStateNotificationListener);
6828
6829 public:
6830 virtual bool init() override;
6831 virtual void free() override;
6832
6833 IOStateNotificationHandler fHandler;
6834 };
6835 OSDefineMetaClassAndStructors(IOStateNotificationListener, OSObject);
6836
6837
6838 bool
init()6839 IOStateNotificationItem::init()
6840 {
6841 return OSObject::init();
6842 }
6843
6844 bool
init()6845 IOStateNotificationListener::init()
6846 {
6847 return OSObject::init();
6848 }
6849
6850 void
free()6851 IOStateNotificationListener::free()
6852 {
6853 if (fHandler) {
6854 Block_release(fHandler);
6855 }
6856 OSObject::free();
6857 }
6858
6859
6860 struct IOServiceStateChangeVars {
6861 IOLock * fLock;
6862 OSDictionary * fItems;
6863 };
6864
6865 IOService *
initialize(void)6866 IOSystemStateNotification::initialize(void)
6867 {
6868 IOSystemStateNotification * me;
6869 IOServiceStateChangeVars * vars;
6870
6871 me = OSTypeAlloc(IOSystemStateNotification);
6872 me->init();
6873 vars = IOMallocType(IOServiceStateChangeVars);
6874 me->reserved->svars = vars;
6875 vars->fLock = IOLockAlloc();
6876 vars->fItems = OSDictionary::withCapacity(16);
6877 {
6878 kern_return_t ret;
6879
6880 gIOSystemStateSleepDescriptionKey = (OSString *)OSSymbol::withCStringNoCopy(kIOSystemStateSleepDescriptionKey);
6881 gIOSystemStateSleepDescriptionHibernateStateKey = OSSymbol::withCStringNoCopy(kIOSystemStateSleepDescriptionHibernateStateKey);
6882 gIOSystemStateSleepDescriptionReasonKey = OSSymbol::withCStringNoCopy(kIOSystemStateSleepDescriptionReasonKey);
6883
6884 ret = me->StateNotificationItemCreate(gIOSystemStateSleepDescriptionKey, NULL);
6885 assert(kIOReturnSuccess == ret);
6886
6887 gIOSystemStateWakeDescriptionKey = (OSString *)OSSymbol::withCStringNoCopy(kIOSystemStateWakeDescriptionKey);
6888 gIOSystemStateWakeDescriptionWakeReasonKey = OSSymbol::withCStringNoCopy(kIOSystemStateWakeDescriptionWakeReasonKey);
6889
6890 ret = me->StateNotificationItemCreate(gIOSystemStateWakeDescriptionKey, NULL);
6891 assert(kIOReturnSuccess == ret);
6892
6893 gIOSystemStateHaltDescriptionKey = (OSString *)OSSymbol::withCStringNoCopy(kIOSystemStateHaltDescriptionKey);
6894 gIOSystemStateHaltDescriptionHaltStateKey = OSSymbol::withCStringNoCopy(kIOSystemStateHaltDescriptionHaltStateKey);
6895
6896 ret = me->StateNotificationItemCreate(gIOSystemStateHaltDescriptionKey, NULL);
6897 assert(kIOReturnSuccess == ret);
6898
6899 gIOSystemStatePowerSourceDescriptionKey = (OSString *)OSSymbol::withCStringNoCopy(kIOSystemStatePowerSourceDescriptionKey);
6900 gIOSystemStatePowerSourceDescriptionACAttachedKey = OSSymbol::withCStringNoCopy(kIOSystemStatePowerSourceDescriptionACAttachedKey);
6901
6902 ret = me->StateNotificationItemCreate(gIOSystemStatePowerSourceDescriptionKey, NULL);
6903 assert(kIOReturnSuccess == ret);
6904 }
6905
6906 return me;
6907 }
6908
6909 bool
serializeProperties(OSSerialize * s) const6910 IOSystemStateNotification::serializeProperties(OSSerialize * s) const
6911 {
6912 IOServiceStateChangeVars * ivars = reserved->svars;
6913
6914 bool ok;
6915 OSDictionary * result;
6916
6917 result = OSDictionary::withCapacity(16);
6918
6919 IOLockLock(ivars->fLock);
6920 ivars->fItems->iterateObjects(^bool (const OSSymbol * key, OSObject * object) {
6921 IOStateNotificationItem * item;
6922
6923 item = (typeof(item))object;
6924 if (!item->fValue) {
6925 return false;
6926 }
6927 result->setObject(key, item->fValue);
6928 return false;
6929 });
6930 IOLockUnlock(ivars->fLock);
6931
6932 ok = result->serialize(s);
6933 OSSafeReleaseNULL(result);
6934
6935 return ok;
6936 }
6937
6938 kern_return_t
setProperties(OSObject * properties)6939 IOSystemStateNotification::setProperties(OSObject * properties)
6940 {
6941 kern_return_t kr;
6942 OSDictionary * dict;
6943 OSDictionary * schema;
6944 OSDictionary * value;
6945 OSString * itemName;
6946
6947 dict = OSDynamicCast(OSDictionary, properties);
6948 if (!dict) {
6949 return kIOReturnBadArgument;
6950 }
6951
6952 if (!IOCurrentTaskHasEntitlement(kIOSystemStateEntitlement)) {
6953 return kIOReturnNotPermitted;
6954 }
6955
6956 if ((schema = OSDynamicCast(OSDictionary, dict->getObject(kIOStateNotificationItemCreateKey)))) {
6957 itemName = OSDynamicCast(OSString, schema->getObject(kIOStateNotificationNameKey));
6958 kr = StateNotificationItemCreate(itemName, schema);
6959 } else if ((value = OSDynamicCast(OSDictionary, dict->getObject(kIOStateNotificationItemSetKey)))) {
6960 itemName = OSDynamicCast(OSString, value->getObject(kIOStateNotificationNameKey));
6961 itemName->retain();
6962 value->removeObject(kIOStateNotificationNameKey);
6963 kr = StateNotificationItemSet(itemName, value);
6964 itemName->release();
6965 } else {
6966 kr = kIOReturnError;
6967 }
6968
6969 return kr;
6970 }
6971
6972 kern_return_t
CopySystemStateNotificationService_Impl(IOService ** outService)6973 IOService::CopySystemStateNotificationService_Impl(IOService ** outService)
6974 {
6975 IOService * service;
6976
6977 service = getSystemStateNotificationService();
6978 service->retain();
6979 *outService = service;
6980
6981 return kIOReturnSuccess;
6982 }
6983
6984 IOStateNotificationItem *
stateNotificationItemCopy(OSString * itemName,OSDictionary * schema)6985 IOService::stateNotificationItemCopy(OSString * itemName, OSDictionary * schema)
6986 {
6987 IOServiceStateChangeVars * ivars = reserved->svars;
6988
6989 const OSSymbol * name;
6990 IOStateNotificationItem * item;
6991
6992 name = OSSymbol::withString(itemName);
6993
6994 IOLockLock(ivars->fLock);
6995 if ((item = (typeof(item))ivars->fItems->getObject(name))) {
6996 item->retain();
6997 } else {
6998 item = OSTypeAlloc(IOStateNotificationItem);
6999 item->init();
7000 item->fListeners = OSSet::withCapacity(16);
7001
7002 if (schema) {
7003 schema->retain();
7004 } else {
7005 schema = OSDictionary::withCapacity(8);
7006 }
7007 schema->setObject(kIOStateNotificationNameKey, name);
7008 item->fSchema = schema;
7009 ivars->fItems->setObject(name, item);
7010 }
7011 IOLockUnlock(ivars->fLock);
7012
7013 OSSafeReleaseNULL(name);
7014
7015 return item;
7016 }
7017
7018 kern_return_t
StateNotificationItemCreate_Impl(OSString * itemName,OSDictionary * schema)7019 IOService::StateNotificationItemCreate_Impl(OSString * itemName, OSDictionary * schema)
7020 {
7021 IOStateNotificationItem * item;
7022
7023 item = stateNotificationItemCopy(itemName, schema);
7024 if (!item) {
7025 return kIOReturnNoMemory;
7026 }
7027 item->release();
7028
7029 return kIOReturnSuccess;
7030 }
7031
7032 kern_return_t
StateNotificationItemSet_Impl(OSString * itemName,OSDictionary * value)7033 IOService::StateNotificationItemSet_Impl(OSString * itemName, OSDictionary * value)
7034 {
7035 IOServiceStateChangeVars * ivars = reserved->svars;
7036
7037 OSSet * listeners;
7038 IOStateNotificationItem * item;
7039
7040 value->retain();
7041 IOLockLock(ivars->fLock);
7042 item = (typeof(item))ivars->fItems->getObject(itemName);
7043 OSSafeReleaseNULL(item->fValue);
7044 item->fValue = value;
7045 listeners = NULL;
7046 if (item->fListeners->getCount()) {
7047 listeners = OSSet::withSet(item->fListeners);
7048 }
7049 IOLockUnlock(ivars->fLock);
7050
7051 if (listeners) {
7052 listeners->iterateObjects(^bool (OSObject * object) {
7053 IOStateNotificationListener * listener;
7054
7055 listener = (typeof(listener))object;
7056 listener->fHandler();
7057 return false;
7058 });
7059 OSSafeReleaseNULL(listeners);
7060 }
7061
7062 return kIOReturnSuccess;
7063 }
7064
7065 kern_return_t
StateNotificationItemCopy_Impl(OSString * itemName,OSDictionary ** outValue)7066 IOService::StateNotificationItemCopy_Impl(OSString * itemName, OSDictionary ** outValue)
7067 {
7068 IOServiceStateChangeVars * ivars = reserved->svars;
7069
7070 kern_return_t ret;
7071 IOStateNotificationItem * item;
7072 OSDictionary * value;
7073
7074 IOLockLock(ivars->fLock);
7075 item = (typeof(item))ivars->fItems->getObject(itemName);
7076 if (item) {
7077 value = item->fValue;
7078 } else {
7079 value = NULL;
7080 }
7081 if (!value) {
7082 ret = kIOReturnNotFound;
7083 } else {
7084 value->retain();
7085 ret = kIOReturnSuccess;
7086 }
7087 IOLockUnlock(ivars->fLock);
7088
7089 *outValue = value;
7090
7091 return ret;
7092 }
7093
7094 kern_return_t
stateNotificationListenerAdd(OSArray * items,IOStateNotificationListenerRef * outRef,IOStateNotificationHandler handler)7095 IOService::stateNotificationListenerAdd(OSArray * items,
7096 IOStateNotificationListenerRef * outRef,
7097 IOStateNotificationHandler handler)
7098 {
7099 IOServiceStateChangeVars * ivars = reserved->svars;
7100
7101 kern_return_t kr __block;
7102 IOStateNotificationListener * listener;
7103
7104 listener = OSTypeAlloc(IOStateNotificationListener);
7105 listener->init();
7106 listener->fHandler = Block_copy(handler);
7107
7108 kr = kIOReturnSuccess;
7109 items->iterateObjects(^bool (OSObject * object) {
7110 OSString * itemName;
7111 IOStateNotificationItem * item;
7112
7113 itemName = OSDynamicCast(OSString, object);
7114 if (!itemName) {
7115 kr = kIOReturnBadArgument;
7116 return true;
7117 }
7118 item = stateNotificationItemCopy(itemName, NULL);
7119 if (!item) {
7120 kr = kIOReturnNoMemory;
7121 return true;
7122 }
7123 IOLockLock(ivars->fLock);
7124 item->fListeners->setObject(listener);
7125 IOLockUnlock(ivars->fLock);
7126 item->release();
7127 return false;
7128 });
7129
7130 if (kIOReturnSuccess != kr) {
7131 stateNotificationListenerRemove(listener);
7132 OSSafeReleaseNULL(listener);
7133 }
7134 *outRef = listener;
7135
7136 return kr;
7137 }
7138
7139
7140 kern_return_t
stateNotificationListenerRemove(IOStateNotificationListenerRef ref)7141 IOService::stateNotificationListenerRemove(IOStateNotificationListenerRef ref)
7142 {
7143 IOServiceStateChangeVars * ivars = reserved->svars;
7144
7145 IOStateNotificationListener * listener;
7146 kern_return_t kr;
7147
7148 kr = kIOReturnSuccess;
7149 listener = (typeof(listener))ref;
7150
7151 IOLockLock(ivars->fLock);
7152 ivars->fItems->iterateObjects(^bool (const OSSymbol * key, OSObject * object) {
7153 IOStateNotificationItem * item;
7154
7155 item = (typeof(item))object;
7156 item->fListeners->removeObject(listener);
7157 return false;
7158 });
7159 IOLockUnlock(ivars->fLock);
7160
7161 return kr;
7162 }
7163
7164
7165
7166 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7167
7168 kern_return_t
Create_Impl(OSString * name,IOUserClient * userClient,IOWorkGroup ** workgroup)7169 IOWorkGroup::Create_Impl(OSString * name, IOUserClient * userClient, IOWorkGroup ** workgroup)
7170 {
7171 IOWorkGroup * inst = NULL;
7172 IOUserUserClient * uc = NULL;
7173 kern_return_t ret = kIOReturnError;
7174 IOUserServer * us;
7175
7176 if (name == NULL) {
7177 ret = kIOReturnBadArgument;
7178 goto finish;
7179 }
7180
7181 if (name->getLength() > kIOWorkGroupMaxNameLength) {
7182 ret = kIOReturnBadArgument;
7183 goto finish;
7184 }
7185
7186 uc = OSDynamicCast(IOUserUserClient, userClient);
7187 if (uc == NULL) {
7188 ret = kIOReturnBadArgument;
7189 goto finish;
7190 }
7191
7192 inst = OSTypeAlloc(IOWorkGroup);
7193 if (!inst->init()) {
7194 inst->free();
7195 inst = NULL;
7196 ret = kIOReturnNoMemory;
7197 goto finish;
7198 }
7199
7200 us = (typeof(us))thread_iokit_tls_get(0);
7201 inst->ivars->userServer = OSDynamicCast(IOUserServer, us);
7202
7203 if (inst->ivars->userServer == NULL) {
7204 ret = kIOReturnBadArgument;
7205 goto finish;
7206 }
7207 inst->ivars->userServer->retain();
7208
7209 inst->ivars->name = name;
7210 inst->ivars->name->retain();
7211
7212 inst->ivars->userClient = uc; // no retain
7213
7214 IOLockLock(uc->fLock);
7215 uc->fWorkGroups->setObject(name, inst);
7216 IOLockUnlock(uc->fLock);
7217 ret = kIOReturnSuccess;
7218
7219 finish:
7220 if (ret != kIOReturnSuccess) {
7221 OSSafeReleaseNULL(inst);
7222 } else {
7223 *workgroup = inst;
7224 }
7225
7226 return ret;
7227 }
7228
7229 kern_return_t
InvalidateKernel_Impl(IOUserClient * client)7230 IOWorkGroup::InvalidateKernel_Impl(IOUserClient * client)
7231 {
7232 IOUserUserClient * uc = OSDynamicCast(IOUserUserClient, client);
7233
7234 if (uc == NULL) {
7235 return kIOReturnBadArgument;
7236 }
7237
7238 if (uc != ivars->userClient) {
7239 return kIOReturnBadArgument;
7240 }
7241
7242 IOLockLock(uc->fLock);
7243 uc->fWorkGroups->removeObject(ivars->name);
7244 IOLockUnlock(uc->fLock);
7245
7246 return kIOReturnSuccess;
7247 }
7248
7249 kern_return_t
SetWorkGroupPort_Impl(mach_port_t port)7250 IOWorkGroup::SetWorkGroupPort_Impl(mach_port_t port)
7251 {
7252 return kIOReturnUnsupported;
7253 }
7254
7255 bool
init()7256 IOWorkGroup::init()
7257 {
7258 if (!OSObject::init()) {
7259 return false;
7260 }
7261 ivars = IOMallocType(IOWorkGroup_IVars);
7262
7263 return true;
7264 }
7265
7266 void
free()7267 IOWorkGroup::free()
7268 {
7269 if (ivars) {
7270 OSSafeReleaseNULL(ivars->userServer);
7271 OSSafeReleaseNULL(ivars->name);
7272 IOFreeType(ivars, IOWorkGroup_IVars);
7273 }
7274
7275 OSObject::free();
7276 }
7277
7278 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7279
7280 kern_return_t
Create_Impl(OSString * name,IOUserClient * userClient,IOEventLink ** eventlink)7281 IOEventLink::Create_Impl(OSString * name, IOUserClient * userClient, IOEventLink ** eventlink)
7282 {
7283 IOEventLink * inst = NULL;
7284 IOUserUserClient * uc = NULL;
7285 IOUserServer * us;
7286 kern_return_t ret = kIOReturnError;
7287
7288 if (name == NULL) {
7289 ret = kIOReturnBadArgument;
7290 goto finish;
7291 }
7292
7293 if (name->getLength() > kIOEventLinkMaxNameLength) {
7294 ret = kIOReturnBadArgument;
7295 goto finish;
7296 }
7297
7298 uc = OSDynamicCast(IOUserUserClient, userClient);
7299 if (uc == NULL) {
7300 ret = kIOReturnBadArgument;
7301 goto finish;
7302 }
7303
7304 inst = OSTypeAlloc(IOEventLink);
7305 if (!inst->init()) {
7306 inst->free();
7307 inst = NULL;
7308 ret = kIOReturnNoMemory;
7309 goto finish;
7310 }
7311
7312 us = (typeof(us))thread_iokit_tls_get(0);
7313 inst->ivars->userServer = OSDynamicCast(IOUserServer, us);
7314
7315 if (inst->ivars->userServer == NULL) {
7316 ret = kIOReturnBadArgument;
7317 goto finish;
7318 }
7319 inst->ivars->userServer->retain();
7320
7321 inst->ivars->name = name;
7322 inst->ivars->name->retain();
7323
7324 inst->ivars->userClient = uc; // no retain
7325
7326 IOLockLock(uc->fLock);
7327 uc->fEventLinks->setObject(name, inst);
7328 IOLockUnlock(uc->fLock);
7329
7330 ret = kIOReturnSuccess;
7331
7332 finish:
7333 if (ret != kIOReturnSuccess) {
7334 OSSafeReleaseNULL(inst);
7335 } else {
7336 *eventlink = inst;
7337 }
7338
7339 return ret;
7340 }
7341
7342 kern_return_t
InvalidateKernel_Impl(IOUserClient * client)7343 IOEventLink::InvalidateKernel_Impl(IOUserClient * client)
7344 {
7345 IOUserUserClient * uc = OSDynamicCast(IOUserUserClient, client);
7346
7347 if (uc == NULL) {
7348 return kIOReturnBadArgument;
7349 }
7350
7351 if (uc != ivars->userClient) {
7352 return kIOReturnBadArgument;
7353 }
7354
7355 IOLockLock(uc->fLock);
7356 uc->fEventLinks->removeObject(ivars->name);
7357 IOLockUnlock(uc->fLock);
7358
7359 return kIOReturnSuccess;
7360 }
7361
7362 bool
init()7363 IOEventLink::init()
7364 {
7365 if (!OSObject::init()) {
7366 return false;
7367 }
7368 ivars = IOMallocType(IOEventLink_IVars);
7369
7370 return true;
7371 }
7372
7373 void
free()7374 IOEventLink::free()
7375 {
7376 if (ivars) {
7377 OSSafeReleaseNULL(ivars->userServer);
7378 OSSafeReleaseNULL(ivars->name);
7379 IOFreeType(ivars, IOEventLink_IVars);
7380 }
7381
7382 OSObject::free();
7383 }
7384
7385 kern_return_t
SetEventlinkPort_Impl(mach_port_t port __unused)7386 IOEventLink::SetEventlinkPort_Impl(mach_port_t port __unused)
7387 {
7388 return kIOReturnUnsupported;
7389 }
7390