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