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