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