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