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