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