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