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