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