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