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