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