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