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