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