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