xref: /xnu-8019.80.24/iokit/Tests/Tests.cpp (revision a325d9c4a84054e40bbe985afedcb50ab80993ea)
1 /*
2  * Copyright (c) 1998-2021 Apple Computer, 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  *
30  */
31 
32 #define TEST_HEADERS    0
33 
34 #if TEST_HEADERS
35 
36 #include <libkern/OSByteOrder.h>
37 #include <libkern/c++/OSArray.h>
38 #include <libkern/c++/OSAllocation.h>
39 #include <libkern/c++/OSBoolean.h>
40 #include <libkern/c++/OSBoundedArray.h>
41 #include <libkern/c++/OSBoundedArrayRef.h>
42 #include <libkern/c++/OSBoundedPtr.h>
43 #include <libkern/c++/OSCollection.h>
44 #include <libkern/c++/OSCollectionIterator.h>
45 #include <libkern/c++/OSContainers.h>
46 #include <libkern/c++/OSCPPDebug.h>
47 #include <libkern/c++/OSData.h>
48 #include <libkern/c++/OSDictionary.h>
49 #include <libkern/c++/OSEndianTypes.h>
50 #include <libkern/c++/OSIterator.h>
51 #include <libkern/c++/OSKext.h>
52 #include <libkern/c++/OSLib.h>
53 #include <libkern/c++/OSMetaClass.h>
54 #include <libkern/c++/OSNumber.h>
55 #include <libkern/c++/OSObject.h>
56 #include <libkern/c++/OSOrderedSet.h>
57 #include <libkern/c++/OSSerialize.h>
58 #include <libkern/c++/OSSet.h>
59 #include <libkern/c++/OSSharedPtr.h>
60 #include <libkern/c++/OSString.h>
61 #include <libkern/c++/OSSymbol.h>
62 #include <libkern/c++/OSUnserialize.h>
63 #include <libkern/crypto/aes.h>
64 #include <libkern/crypto/aesxts.h>
65 #include <libkern/crypto/crypto_internal.h>
66 #include <libkern/crypto/des.h>
67 #include <libkern/crypto/md5.h>
68 #include <libkern/crypto/register_crypto.h>
69 #include <libkern/crypto/sha1.h>
70 #include <libkern/crypto/sha2.h>
71 #include <libkern/kernel_mach_header.h>
72 #include <libkern/kext_request_keys.h>
73 #include <libkern/kxld.h>
74 #include <libkern/kxld_types.h>
75 #include <libkern/locks.h>
76 #include <libkern/mkext.h>
77 #include <libkern/OSAtomic.h>
78 #include <libkern/OSBase.h>
79 #include <libkern/OSDebug.h>
80 #include <libkern/OSKextLib.h>
81 #include <libkern/OSKextLibPrivate.h>
82 #include <libkern/OSReturn.h>
83 #include <libkern/OSSerializeBinary.h>
84 #include <libkern/OSTypes.h>
85 #include <libkern/prelink.h>
86 #include <libkern/stack_protector.h>
87 #include <libkern/sysctl.h>
88 #include <libkern/tree.h>
89 #include <libkern/zconf.h>
90 #include <libkern/zlib.h>
91 
92 #include <IOKit/AppleKeyStoreInterface.h>
93 #include <IOKit/assert.h>
94 #include <IOKit/IOBSD.h>
95 #include <IOKit/IOBufferMemoryDescriptor.h>
96 #include <IOKit/IOCatalogue.h>
97 #include <IOKit/IOCommand.h>
98 #include <IOKit/IOCommandGate.h>
99 #include <IOKit/IOCommandPool.h>
100 #include <IOKit/IOCommandQueue.h>
101 #include <IOKit/IOConditionLock.h>
102 #include <IOKit/IOCPU.h>
103 //#include <IOKit/IODataQueue.h>
104 #include <IOKit/IODataQueueShared.h>
105 #include <IOKit/IODeviceMemory.h>
106 #include <IOKit/IODeviceTreeSupport.h>
107 #include <IOKit/IODMACommand.h>
108 #include <IOKit/IODMAController.h>
109 #include <IOKit/IODMAEventSource.h>
110 #include <IOKit/IOEventSource.h>
111 #include <IOKit/IOFilterInterruptEventSource.h>
112 #include <IOKit/IOHibernatePrivate.h>
113 #include <IOKit/IOInterleavedMemoryDescriptor.h>
114 #include <IOKit/IOInterruptAccounting.h>
115 #include <IOKit/IOInterruptAccountingPrivate.h>
116 #include <IOKit/IOInterruptController.h>
117 #include <IOKit/IOInterruptEventSource.h>
118 #include <IOKit/IOInterrupts.h>
119 #include <IOKit/IOKernelReporters.h>
120 #include <IOKit/IOKernelReportStructs.h>
121 #include <IOKit/IOKitDebug.h>
122 #include <IOKit/IOKitDiagnosticsUserClient.h>
123 #include <IOKit/IOKitKeys.h>
124 #include <IOKit/IOKitKeysPrivate.h>
125 #include <IOKit/IOKitServer.h>
126 #include <IOKit/IOLib.h>
127 #include <IOKit/IOLocks.h>
128 #include <IOKit/IOLocksPrivate.h>
129 #include <IOKit/IOMapper.h>
130 #include <IOKit/IOMemoryCursor.h>
131 #include <IOKit/IOMemoryDescriptor.h>
132 #include <IOKit/IOMessage.h>
133 #include <IOKit/IOMultiMemoryDescriptor.h>
134 #include <IOKit/IONotifier.h>
135 #include <IOKit/IONVRAM.h>
136 #include <IOKit/IOPlatformExpert.h>
137 #include <IOKit/IOPolledInterface.h>
138 #include <IOKit/IORangeAllocator.h>
139 #include <IOKit/IORegistryEntry.h>
140 #include <IOKit/IOReportMacros.h>
141 #include <IOKit/IOReportTypes.h>
142 #include <IOKit/IOReturn.h>
143 #include <IOKit/IOService.h>
144 #include <IOKit/IOServicePM.h>
145 #include <IOKit/IOSharedDataQueue.h>
146 #include <IOKit/IOSharedLock.h>
147 #include <IOKit/IOStatistics.h>
148 #include <IOKit/IOStatisticsPrivate.h>
149 #include <IOKit/IOSubMemoryDescriptor.h>
150 #include <IOKit/IOSyncer.h>
151 #include <IOKit/IOTimerEventSource.h>
152 #include <IOKit/IOTimeStamp.h>
153 #include <IOKit/IOTypes.h>
154 #include <IOKit/IOUserClient.h>
155 #include <IOKit/IOWorkLoop.h>
156 #include <IOKit/nvram/IONVRAMController.h>
157 #include <IOKit/OSMessageNotification.h>
158 #include <IOKit/platform/AppleMacIO.h>
159 #include <IOKit/platform/AppleMacIODevice.h>
160 #include <IOKit/platform/AppleNMI.h>
161 #include <IOKit/platform/ApplePlatformExpert.h>
162 #include <IOKit/power/IOPwrController.h>
163 #include <IOKit/pwr_mgt/IOPM.h>
164 #include <IOKit/pwr_mgt/IOPMinformee.h>
165 #include <IOKit/pwr_mgt/IOPMinformeeList.h>
166 #include <IOKit/pwr_mgt/IOPMLibDefs.h>
167 #include <IOKit/pwr_mgt/IOPMlog.h>
168 #include <IOKit/pwr_mgt/IOPMPowerSource.h>
169 #include <IOKit/pwr_mgt/IOPMPowerSourceList.h>
170 #include <IOKit/pwr_mgt/IOPMpowerState.h>
171 #include <IOKit/pwr_mgt/IOPMPrivate.h>
172 #include <IOKit/pwr_mgt/IOPowerConnection.h>
173 #include <IOKit/pwr_mgt/RootDomain.h>
174 #include <IOKit/rtc/IORTCController.h>
175 #include <IOKit/system.h>
176 #include <IOKit/system_management/IOWatchDogTimer.h>
177 
178 #endif /* TEST_HEADERS */
179 
180 #include <sys/sysctl.h>
181 #include <libkern/c++/OSData.h>
182 #include <IOKit/IOService.h>
183 #include <IOKit/IOUserClient.h>
184 #include "Tests.h"
185 
186 
187 #if DEVELOPMENT || DEBUG
188 
189 #include <IOKit/IOWorkLoop.h>
190 #include <IOKit/IOTimerEventSource.h>
191 #include <IOKit/IOInterruptEventSource.h>
192 #include <IOKit/IOCommandGate.h>
193 #include <IOKit/IOPlatformExpert.h>
194 #include <IOKit/IOSharedDataQueue.h>
195 #include <IOKit/IODataQueueShared.h>
196 #include <IOKit/IOServiceStateNotificationEventSource.h>
197 #include <IOKit/IOKitKeysPrivate.h>
198 #include <IOKit/IOKitServer.h>
199 #include <IOKit/IOBSD.h>
200 #include <kern/ipc_kobject.h>
201 #include <libkern/Block.h>
202 #include <libkern/Block_private.h>
203 #include <libkern/c++/OSAllocation.h>
204 #include <libkern/c++/OSBoundedArray.h>
205 #include <libkern/c++/OSBoundedArrayRef.h>
206 #include <libkern/c++/OSBoundedPtr.h>
207 #include <libkern/c++/OSSharedPtr.h>
208 #include <os/cpp_util.h>
209 
210 static uint64_t gIOWorkLoopTestDeadline;
211 
212 static void
TESAction(OSObject * owner,IOTimerEventSource * tes)213 TESAction(OSObject * owner, IOTimerEventSource * tes)
214 {
215 	if (mach_absolute_time() < gIOWorkLoopTestDeadline) {
216 		tes->setTimeout(1, kMicrosecondScale);
217 	}
218 }
219 
220 static int
IOWorkLoopTest(int newValue)221 IOWorkLoopTest(int newValue)
222 {
223 	IOReturn err;
224 	uint32_t idx;
225 	IOWorkLoop * wl;
226 	IOTimerEventSource * tes;
227 	IOInterruptEventSource * ies;
228 
229 	wl = IOWorkLoop::workLoop();
230 	assert(wl);
231 	tes = IOTimerEventSource::timerEventSource(kIOTimerEventSourceOptionsPriorityWorkLoop, wl, &TESAction);
232 	assert(tes);
233 	err = wl->addEventSource(tes);
234 	assert(kIOReturnSuccess == err);
235 	clock_interval_to_deadline(100, kMillisecondScale, &gIOWorkLoopTestDeadline);
236 	for (idx = 0; mach_absolute_time() < gIOWorkLoopTestDeadline; idx++) {
237 		tes->setTimeout(idx & 1023, kNanosecondScale);
238 	}
239 	tes->cancelTimeout();
240 	wl->removeEventSource(tes);
241 	tes->release();
242 
243 	int value = 3;
244 
245 	tes = IOTimerEventSource::timerEventSource(kIOTimerEventSourceOptionsDefault, wl, ^(IOTimerEventSource * tes){
246 		kprintf("wl %p, value %d\n", wl, value);
247 	});
248 	err = wl->addEventSource(tes);
249 	assert(kIOReturnSuccess == err);
250 
251 	value = 2;
252 	tes->setTimeout(1, kNanosecondScale);
253 	IOSleep(1);
254 	wl->removeEventSource(tes);
255 	tes->release();
256 
257 	ies = IOInterruptEventSource::interruptEventSource(wl, NULL, 0, ^void (IOInterruptEventSource *sender, int count){
258 		kprintf("ies block %p, %d\n", sender, count);
259 	});
260 
261 	assert(ies);
262 	kprintf("ies %p\n", ies);
263 	err = wl->addEventSource(ies);
264 	assert(kIOReturnSuccess == err);
265 	ies->interruptOccurred(NULL, NULL, 0);
266 	IOSleep(1);
267 	ies->interruptOccurred(NULL, NULL, 0);
268 	IOSleep(1);
269 	wl->removeEventSource(ies);
270 	ies->release();
271 
272 	wl->release();
273 
274 	return 0;
275 }
276 
277 static int
OSCollectionTest(int newValue)278 OSCollectionTest(int newValue)
279 {
280 	OSArray * array = OSArray::withCapacity(8);
281 	array->setObject(kOSBooleanTrue);
282 	array->setObject(kOSBooleanFalse);
283 	array->setObject(kOSBooleanFalse);
284 	array->setObject(kOSBooleanTrue);
285 	array->setObject(kOSBooleanFalse);
286 	array->setObject(kOSBooleanTrue);
287 
288 	__block unsigned int index;
289 	index = 0;
290 	array->iterateObjects(^bool (OSObject * obj) {
291 		kprintf("%d:%d ", index, (obj == kOSBooleanTrue) ? 1 : (obj == kOSBooleanFalse) ? 0 : 2);
292 		index++;
293 		return false;
294 	});
295 	kprintf("\n");
296 	array->release();
297 
298 	OSDictionary * dict = IOService::resourceMatching("hello");
299 	assert(dict);
300 	index = 0;
301 	dict->iterateObjects(^bool (const OSSymbol * sym, OSObject * obj) {
302 		OSString * str = OSDynamicCast(OSString, obj);
303 		assert(str);
304 		kprintf("%d:%s=%s\n", index, sym->getCStringNoCopy(), str->getCStringNoCopy());
305 		index++;
306 		return false;
307 	});
308 	dict->release();
309 
310 	OSSerializer * serializer = OSSerializer::withBlock(^bool (OSSerialize * s){
311 		return gIOBSDUnitKey->serialize(s);
312 	});
313 	assert(serializer);
314 	IOService::getPlatform()->setProperty("OSSerializer_withBlock", serializer);
315 	serializer->release();
316 
317 	OSString * ab = OSString::withCString("abcdef", 2);
318 	assert(strcmp(ab->getCStringNoCopy(), "ab") == 0);
319 	OSString * defgh = OSString::withCString("defgh", 10);
320 	assert(strcmp(defgh->getCStringNoCopy(), "defgh") == 0);
321 	OSString * zyxwvut = OSString::withCString("zyxwvut", 7);
322 	assert(strcmp(zyxwvut->getCStringNoCopy(), "zyxwvut") == 0);
323 	OSSafeReleaseNULL(ab);
324 	OSSafeReleaseNULL(defgh);
325 	OSSafeReleaseNULL(zyxwvut);
326 
327 	return 0;
328 }
329 
330 static int
OSAllocationTests(int)331 OSAllocationTests(int)
332 {
333 	OSAllocation<int> ints(100, OSAllocateMemory);
334 	assert(ints);
335 
336 	{
337 		int counter = 0;
338 		for (int& i : ints) {
339 			i = counter++;
340 		}
341 	}
342 
343 	{
344 		int counter = 0;
345 		for (int& i : ints) {
346 			assert(i == counter);
347 			++counter;
348 		}
349 	}
350 
351 	OSAllocation<int> arrayZero(100, OSAllocateMemoryZero);
352 	assert(arrayZero);
353 	for (const auto& i : arrayZero) {
354 		assert(i == 0);
355 	}
356 
357 	// Make sure we can have two-level OSAllocations
358 	{
359 		OSAllocation<OSAllocation<int> > testArray(10, OSAllocateMemory);
360 		for (int i = 0; i < 10; i++) {
361 			testArray[i] = OSAllocation<int>(10, OSAllocateMemory);
362 			for (int j = 0; j < 10; ++j) {
363 				testArray[i][j] = i + j;
364 			}
365 		}
366 
367 		for (int i = 0; i < 10; i++) {
368 			for (int j = 0; j < 10; ++j) {
369 				assert(testArray[i][j] == i + j);
370 			}
371 		}
372 	}
373 
374 	return 0;
375 }
376 
377 static int
OSDataAllocationTests(int)378 OSDataAllocationTests(int)
379 {
380 	OSDataAllocation<int> ints(100, OSAllocateMemory);
381 	assert(ints);
382 
383 	{
384 		int counter = 0;
385 		for (int& i : ints) {
386 			i = counter++;
387 		}
388 	}
389 
390 	{
391 		int counter = 0;
392 		for (const int& i : ints) {
393 			assert(i == counter);
394 			++counter;
395 		}
396 	}
397 
398 	OSDataAllocation<int> arrayZero(100, OSAllocateMemoryZero);
399 	assert(arrayZero);
400 	for (const auto& i : arrayZero) {
401 		assert(i == 0);
402 	}
403 
404 	return 0;
405 }
406 
407 static int
OSBoundedArrayTests(int)408 OSBoundedArrayTests(int)
409 {
410 	OSBoundedArray<int, 5> ints = {0, 1, 2, 3, 4};
411 	assert(ints.size() == 5);
412 
413 	{
414 		int counter = 0;
415 		for (int& i : ints) {
416 			i = counter++;
417 		}
418 	}
419 
420 	{
421 		int counter = 0;
422 		for (int& i : ints) {
423 			assert(i == counter);
424 			++counter;
425 		}
426 	}
427 
428 	return 0;
429 }
430 
431 static int
OSBoundedArrayRefTests(int)432 OSBoundedArrayRefTests(int)
433 {
434 	OSBoundedArray<int, 5> storage = {0, 1, 2, 3, 4};
435 	OSBoundedArrayRef<int> ints(storage);
436 	assert(ints);
437 
438 	{
439 		int counter = 0;
440 		for (int& i : ints) {
441 			i = counter++;
442 		}
443 	}
444 
445 	{
446 		int counter = 0;
447 		for (int& i : ints) {
448 			assert(i == counter);
449 			++counter;
450 		}
451 	}
452 
453 	return 0;
454 }
455 
456 class OSArraySubclass : public OSArray {
457 	OSDeclareDefaultStructors(OSArraySubclass);
458 public:
459 	static OSArraySubclass * withCapacity(unsigned int inCapacity);
460 	virtual unsigned int iteratorSize() const APPLE_KEXT_OVERRIDE;
461 };
462 
463 OSDefineMetaClassAndStructors(OSArraySubclass, OSArray);
464 
465 OSArraySubclass *
withCapacity(unsigned int inCapacity)466 OSArraySubclass::withCapacity(unsigned int inCapacity)
467 {
468 	OSArraySubclass * me = OSTypeAlloc(OSArraySubclass);
469 
470 	if (me && !me->initWithCapacity(inCapacity)) {
471 		return nullptr;
472 	}
473 
474 	return me;
475 }
476 
477 unsigned int
iteratorSize() const478 OSArraySubclass::iteratorSize() const
479 {
480 	unsigned int result = 64;
481 	// Has to be larger than the OSArray iterator size to prevent out-of-bounds writes
482 	assert(result >= OSArray::iteratorSize());
483 	return result;
484 }
485 
486 class OSCISubclass : public OSCollectionIterator {
487 	OSDeclareDefaultStructors(OSCISubclass);
488 public:
489 	static OSCISubclass * withCollection(const OSCollection * inColl);
490 };
491 
492 OSDefineMetaClassAndStructors(OSCISubclass, OSCollectionIterator);
493 
494 OSCISubclass *
withCollection(const OSCollection * inColl)495 OSCISubclass::withCollection(const OSCollection * inColl)
496 {
497 	OSCISubclass * me = OSTypeAlloc(OSCISubclass);
498 
499 	if (me && !me->initWithCollection(inColl)) {
500 		return nullptr;
501 	}
502 
503 	return me;
504 }
505 
506 static int
OSCollectionIteratorTests(int)507 OSCollectionIteratorTests(int)
508 {
509 	OSArray * array = OSArray::withCapacity(0);
510 	OSString * firstObj = OSString::withCString("test object");
511 	OSString * secondObj = OSString::withCString("test object 2");
512 	OSObject * current = NULL;
513 	OSCollectionIterator * osci = NULL;
514 	OSCISubclass * osciSubclass = NULL;
515 	size_t index = 0;
516 	array->setObject(firstObj);
517 	array->setObject(secondObj);
518 
519 	// Test iteration over a normal OSArray
520 	osci = OSCollectionIterator::withCollection(array);
521 	assert(osci != NULL);
522 
523 	index = 0;
524 	while ((current = osci->getNextObject()) != NULL) {
525 		if (index == 0) {
526 			assert(current == firstObj);
527 		} else if (index == 1) {
528 			assert(current == secondObj);
529 		} else {
530 			panic("index out of range");
531 		}
532 		index++;
533 	}
534 
535 	OSSafeReleaseNULL(osci);
536 
537 	// Test iteration with a OSCollectionIterator subclass over a normal OSArray
538 	osciSubclass = OSCISubclass::withCollection(array);
539 	assert(osciSubclass != NULL);
540 
541 	index = 0;
542 	while ((current = osciSubclass->getNextObject()) != NULL) {
543 		if (index == 0) {
544 			assert(current == firstObj);
545 		} else if (index == 1) {
546 			assert(current == secondObj);
547 		} else {
548 			panic("index out of range");
549 		}
550 		index++;
551 	}
552 
553 	OSSafeReleaseNULL(osciSubclass);
554 
555 	OSSafeReleaseNULL(array);
556 
557 	// Create the OSArray subclass
558 	OSArraySubclass * arraySubclass = OSArraySubclass::withCapacity(0);
559 	arraySubclass->setObject(firstObj);
560 	arraySubclass->setObject(secondObj);
561 	// Test iteration over a subclassed OSArray, with a large iterator size
562 	osci = OSCollectionIterator::withCollection(arraySubclass);
563 	assert(osci != NULL);
564 
565 	index = 0;
566 	while ((current = osci->getNextObject()) != NULL) {
567 		if (index == 0) {
568 			assert(current == firstObj);
569 		} else if (index == 1) {
570 			assert(current == secondObj);
571 		} else {
572 			panic("index out of range");
573 		}
574 		index++;
575 	}
576 
577 	OSSafeReleaseNULL(osci);
578 
579 	// Test iteration with a OSCollectionIterator subclass over a subclassed OSArray,
580 	// with a large iterator size.
581 	osciSubclass = OSCISubclass::withCollection(arraySubclass);
582 	assert(osciSubclass != NULL);
583 
584 	index = 0;
585 	while ((current = osciSubclass->getNextObject()) != NULL) {
586 		if (index == 0) {
587 			assert(current == firstObj);
588 		} else if (index == 1) {
589 			assert(current == secondObj);
590 		} else {
591 			panic("index out of range");
592 		}
593 		index++;
594 	}
595 
596 	OSSafeReleaseNULL(osciSubclass);
597 
598 	OSSafeReleaseNULL(arraySubclass);
599 	OSSafeReleaseNULL(firstObj);
600 	OSSafeReleaseNULL(secondObj);
601 
602 	return 0;
603 }
604 
605 static int
OSBoundedPtrTests(int)606 OSBoundedPtrTests(int)
607 {
608 	int array[5] = {55, 66, 77, 88, 99};
609 	OSBoundedPtr<int> begin(&array[0], &array[0], &array[5]);
610 	OSBoundedPtr<int> end(&array[5], &array[0], &array[5]);
611 
612 	{
613 		int counter = 0;
614 		for (OSBoundedPtr<int> b = begin; b != end; ++b) {
615 			*b = counter++;
616 		}
617 	}
618 
619 	{
620 		int counter = 0;
621 		for (OSBoundedPtr<int> b = begin; b != end; ++b) {
622 			assert(*b == counter);
623 			++counter;
624 		}
625 	}
626 
627 	return 0;
628 }
629 
630 static int
IOSharedDataQueue_44636964(__unused int newValue)631 IOSharedDataQueue_44636964(__unused int newValue)
632 {
633 	IOSharedDataQueue* sd = IOSharedDataQueue::withCapacity(DATA_QUEUE_ENTRY_HEADER_SIZE + sizeof(UInt64));
634 	UInt64 data = 0x11223344aa55aa55;
635 	UInt32 data2 = 0x44332211;
636 	UInt32 size = sizeof(UInt32);
637 	/* enqueue moves tail to end */
638 	sd->enqueue(&data, sizeof(UInt64));
639 	/* dequeue moves head to end */
640 	sd->dequeue(&data, &size);
641 	/* Tail wraps around, head is still at end */
642 	sd->enqueue(&data2, sizeof(UInt32));
643 	/* something in the queue so peek() should return non-null */
644 	assert(sd->peek() != NULL);
645 	sd->release();
646 	return KERN_SUCCESS;
647 }
648 
649 #if 0
650 #include <IOKit/IOUserClient.h>
651 class TestUserClient : public IOUserClient
652 {
653 	OSDeclareDefaultStructors(TestUserClient);
654 	virtual void stop( IOService *provider) APPLE_KEXT_OVERRIDE;
655 	virtual bool finalize(IOOptionBits options) APPLE_KEXT_OVERRIDE;
656 	virtual IOReturn externalMethod( uint32_t selector,
657 	    IOExternalMethodArguments * arguments,
658 	    IOExternalMethodDispatch * dispatch,
659 	    OSObject * target,
660 	    void * reference ) APPLE_KEXT_OVERRIDE;
661 };
662 
663 void
664 TestUserClient::stop( IOService *provider)
665 {
666 	kprintf("TestUserClient::stop\n");
667 }
668 bool
669 TestUserClient::finalize(IOOptionBits options)
670 {
671 	kprintf("TestUserClient::finalize\n");
672 	return true;
673 }
674 IOReturn
675 TestUserClient::externalMethod( uint32_t selector,
676     IOExternalMethodArguments * arguments,
677     IOExternalMethodDispatch * dispatch,
678     OSObject * target,
679     void * reference )
680 {
681 	getProvider()->terminate();
682 	IOSleep(500);
683 	return 0;
684 }
685 OSDefineMetaClassAndStructors(TestUserClient, IOUserClient);
686 #endif
687 
688 static int
IOServiceTest(int newValue)689 IOServiceTest(int newValue)
690 {
691 	OSDictionary      * matching;
692 	IONotifier        * note;
693 	__block IOService * found;
694 
695 #if 0
696 	found = new IOService;
697 	found->init();
698 	found->setName("IOTestUserClientProvider");
699 	found->attach(IOService::getPlatform());
700 	found->setProperty("IOUserClientClass", "TestUserClient");
701 	found->registerService();
702 #endif
703 
704 	matching = IOService::serviceMatching("IOPlatformExpert");
705 	assert(matching);
706 	found = nullptr;
707 	note = IOService::addMatchingNotification(gIOMatchedNotification, matching, 0,
708 	    ^bool (IOService * newService, IONotifier * notifier) {
709 		kprintf("found %s, %d\n", newService->getName(), newService->getRetainCount());
710 		found = newService;
711 		found->retain();
712 		return true;
713 	}
714 	    );
715 	assert(note);
716 	assert(found);
717 	matching->release();
718 	note->remove();
719 
720 	note = found->registerInterest(gIOBusyInterest,
721 	    ^IOReturn (uint32_t messageType, IOService * provider,
722 	    void   * messageArgument, size_t argSize) {
723 		kprintf("%p messageType 0x%08x %p\n", provider, messageType, messageArgument);
724 		return kIOReturnSuccess;
725 	});
726 	assert(note);
727 	IOSleep(1 * 1000);
728 	note->remove();
729 	found->release();
730 
731 	return 0;
732 }
733 
734 static void
OSStaticPtrCastTests()735 OSStaticPtrCastTests()
736 {
737 	// const& overload
738 	{
739 		OSSharedPtr<OSDictionary> const dict = OSMakeShared<OSDictionary>();
740 		OSSharedPtr<OSCollection> collection = OSStaticPtrCast<OSCollection>(dict);
741 		assert(collection == dict);
742 	}
743 	{
744 		OSSharedPtr<OSDictionary> const dict = nullptr;
745 		OSSharedPtr<OSCollection> collection = OSStaticPtrCast<OSCollection>(dict);
746 		assert(collection == nullptr);
747 	}
748 	// && overload
749 	{
750 		OSSharedPtr<OSDictionary> dict = OSMakeShared<OSDictionary>();
751 		OSDictionary* oldDict = dict.get();
752 		OSSharedPtr<OSCollection> collection = OSStaticPtrCast<OSCollection>(os::move(dict));
753 		assert(collection.get() == oldDict);
754 		assert(dict == nullptr);
755 	}
756 	{
757 		OSSharedPtr<OSDictionary> dict = nullptr;
758 		OSSharedPtr<OSCollection> collection = OSStaticPtrCast<OSCollection>(os::move(dict));
759 		assert(collection == nullptr);
760 		assert(dict == nullptr);
761 	}
762 }
763 
764 static void
OSConstPtrCastTests()765 OSConstPtrCastTests()
766 {
767 	// const& overload
768 	{
769 		OSSharedPtr<OSDictionary const> const dict = OSMakeShared<OSDictionary>();
770 		OSSharedPtr<OSDictionary> dict2 = OSConstPtrCast<OSDictionary>(dict);
771 		assert(dict2 == dict);
772 	}
773 	{
774 		OSSharedPtr<OSDictionary const> const dict = OSMakeShared<OSDictionary>();
775 		OSSharedPtr<OSDictionary const> dict2 = OSConstPtrCast<OSDictionary const>(dict);
776 		assert(dict2 == dict);
777 	}
778 	{
779 		OSSharedPtr<OSDictionary const> const dict = nullptr;
780 		OSSharedPtr<OSDictionary> dict2 = OSConstPtrCast<OSDictionary>(dict);
781 		assert(dict2 == nullptr);
782 	}
783 	{
784 		OSSharedPtr<OSDictionary const> const dict = nullptr;
785 		OSSharedPtr<OSDictionary const> dict2 = OSConstPtrCast<OSDictionary const>(dict);
786 		assert(dict2 == nullptr);
787 	}
788 
789 	// && overload
790 	{
791 		OSSharedPtr<OSDictionary const> dict = OSMakeShared<OSDictionary>();
792 		OSDictionary const* oldDict = dict.get();
793 		OSSharedPtr<OSDictionary> dict2 = OSConstPtrCast<OSDictionary>(os::move(dict));
794 		assert(dict == nullptr);
795 		assert(dict2 == oldDict);
796 	}
797 	{
798 		OSSharedPtr<OSDictionary const> dict = nullptr;
799 		OSSharedPtr<OSDictionary> dict2 = OSConstPtrCast<OSDictionary>(os::move(dict));
800 		assert(dict == nullptr);
801 		assert(dict2 == nullptr);
802 	}
803 }
804 
805 static void
OSDynamicPtrCastTests()806 OSDynamicPtrCastTests()
807 {
808 	OSSharedPtr<OSDictionary> const dict = OSMakeShared<OSDictionary>();
809 	{
810 		OSSharedPtr<OSCollection> collection = OSDynamicPtrCast<OSCollection>(dict);
811 		assert(collection != nullptr);
812 	}
813 	{
814 		OSSharedPtr<OSArray> array = OSDynamicPtrCast<OSArray>(dict);
815 		assert(array == nullptr);
816 		assert(dict != nullptr);
817 	}
818 	{
819 		OSTaggedSharedPtr<OSCollection, OSCollection> taggedDict(dict.get(), OSRetain);
820 		OSTaggedSharedPtr<OSCollection, OSCollection> collection = OSDynamicPtrCast<OSCollection>(taggedDict);
821 		assert(collection != nullptr);
822 	}
823 	{
824 		OSTaggedSharedPtr<OSCollection, OSCollection> taggedDict(dict.get(), OSRetain);
825 		OSTaggedSharedPtr<OSArray, OSCollection> array = OSDynamicPtrCast<OSArray>(taggedDict);
826 		assert(array == nullptr);
827 		assert(dict != nullptr);
828 	}
829 	{
830 		OSSharedPtr<OSCollection> collection = OSDynamicPtrCast<OSCollection>(dict);
831 		assert(collection.get() == OSDynamicCast(OSDictionary, dict.get()));
832 		OSSharedPtr<OSDictionary> newDict = OSDynamicPtrCast<OSDictionary>(os::move(collection));
833 		assert(collection == nullptr);
834 		assert(newDict != nullptr);
835 		assert(newDict.get() == dict.get());
836 	}
837 }
838 
839 
840 class IOTestUserNotification : public IOUserNotification
841 {
842 	OSDeclareDefaultStructors(IOTestUserNotification);
843 };
844 
845 OSDefineMetaClassAndStructors(IOTestUserNotification, IOUserNotification)
846 
847 struct IOUserNotificationTestThreadArgs {
848 	IOTestUserNotification * userNotify;
849 	IOLock * lock;
850 	size_t * completed;
851 	size_t iterations;
852 };
853 
854 static bool
IOUserNotificationMatchingHandler(void * target __unused,void * ref __unused,IOService * newService __unused,IONotifier * notifier __unused)855 IOUserNotificationMatchingHandler( void * target __unused,
856     void * ref __unused, IOService * newService __unused, IONotifier * notifier __unused )
857 {
858 	return true;
859 }
860 
861 static void
IOUserNotificationTestThread(void * arg,wait_result_t result __unused)862 IOUserNotificationTestThread(void * arg, wait_result_t result __unused)
863 {
864 	IOUserNotificationTestThreadArgs * threadArgs = (IOUserNotificationTestThreadArgs *)arg;
865 
866 	OSDictionary * dict = OSDictionary::withCapacity(0);
867 	OSString * rootPath = OSString::withCStringNoCopy(":/");
868 	dict->setObject(gIOPathMatchKey, rootPath);
869 
870 	for (size_t i = 0; i < threadArgs->iterations; i++) {
871 		if (i % 2 == 0) {
872 			IONotifier * notify = IOService::addMatchingNotification( gIOWillTerminateNotification, dict,
873 			    &IOUserNotificationMatchingHandler, NULL );
874 			threadArgs->userNotify->setNotification(notify);
875 		} else {
876 			threadArgs->userNotify->setNotification(NULL);
877 		}
878 	}
879 
880 	threadArgs->userNotify->setNotification(NULL);
881 	OSSafeReleaseNULL(rootPath);
882 	OSSafeReleaseNULL(dict);
883 
884 	IOLockLock(threadArgs->lock);
885 	*threadArgs->completed = *threadArgs->completed + 1;
886 	IOLockWakeup(threadArgs->lock, (event_t)threadArgs->completed, true);
887 	IOLockUnlock(threadArgs->lock);
888 }
889 
890 static int
IOUserNotificationTests(__unused int newValue)891 IOUserNotificationTests(__unused int newValue)
892 {
893 	constexpr size_t numThreads = 10;
894 	constexpr size_t numIterations = 500000;
895 	IOTestUserNotification * userNotify = OSTypeAlloc(IOTestUserNotification);
896 	IOLock * lock = IOLockAlloc();
897 	size_t threadsCompleted;
898 	size_t i = 0;
899 	thread_t threads[numThreads];
900 	kern_return_t kr;
901 	bool result;
902 
903 	struct IOUserNotificationTestThreadArgs threadArgs = {
904 		.userNotify = userNotify,
905 		.lock = lock,
906 		.completed = &threadsCompleted,
907 		.iterations = numIterations,
908 	};
909 
910 	result = userNotify->init();
911 	assert(result);
912 
913 	for (i = 0; i < numThreads; i++) {
914 		kr = kernel_thread_start(&IOUserNotificationTestThread, (void *)&threadArgs, &threads[i]);
915 		assert(kr == KERN_SUCCESS);
916 	}
917 
918 	IOLockLock(lock);
919 	while (threadsCompleted < numThreads) {
920 		IOLockSleep(lock, &threadsCompleted, THREAD_UNINT);
921 		IOLog("%s: Threads completed: %zu/%zu\n", __func__, threadsCompleted, numThreads);
922 	}
923 	IOLockUnlock(lock);
924 
925 	for (i = 0; i < numThreads; i++) {
926 		thread_deallocate(threads[i]);
927 	}
928 
929 	userNotify->setNotification(NULL);
930 
931 	OSSafeReleaseNULL(userNotify);
932 	IOLockFree(lock);
933 
934 	return KERN_SUCCESS;
935 }
936 
937 static void
IOServiceMatchingSharedPtrTests()938 IOServiceMatchingSharedPtrTests()
939 {
940 	const OSSymbol * name = OSSymbol::withCString("name");
941 	const OSSymbol * value = OSSymbol::withCString("value");
942 
943 	{
944 		OSSharedPtr<OSDictionary> table;
945 		OSSharedPtr<OSDictionary> result = IOService::serviceMatching("name", table);
946 		assert(result);
947 		assert(result->getRetainCount() == 1);
948 
949 		table = result;
950 		assert(table->getRetainCount() == 2);
951 		OSSharedPtr<OSDictionary> result2 = IOService::serviceMatching("name", table);
952 		assert(result2);
953 		assert(result2 == table);
954 		assert(result2->getRetainCount() == 3);
955 	}
956 
957 	{
958 		OSSharedPtr<OSDictionary> table;
959 		OSSharedPtr<OSDictionary> result = IOService::serviceMatching(name, table);
960 		assert(result);
961 		assert(result->getRetainCount() == 1);
962 
963 		table = result;
964 		assert(table->getRetainCount() == 2);
965 		OSSharedPtr<OSDictionary> result2 = IOService::serviceMatching(name, table);
966 		assert(result2);
967 		assert(result2 == table);
968 		assert(result2->getRetainCount() == 3);
969 	}
970 
971 	{
972 		OSSharedPtr<OSDictionary> table;
973 		OSSharedPtr<OSDictionary> result = IOService::nameMatching("name", table);
974 		assert(result);
975 		assert(result->getRetainCount() == 1);
976 
977 		table = result;
978 		assert(table->getRetainCount() == 2);
979 		OSSharedPtr<OSDictionary> result2 = IOService::nameMatching("name", table);
980 		assert(result2);
981 		assert(result2 == table);
982 		assert(result2->getRetainCount() == 3);
983 	}
984 
985 	{
986 		OSSharedPtr<OSDictionary> table;
987 		OSSharedPtr<OSDictionary> result = IOService::nameMatching(name, table);
988 		assert(result);
989 		assert(result->getRetainCount() == 1);
990 
991 		table = result;
992 		assert(table->getRetainCount() == 2);
993 		OSSharedPtr<OSDictionary> result2 = IOService::nameMatching(name, table);
994 		assert(result2);
995 		assert(result2 == table);
996 		assert(result2->getRetainCount() == 3);
997 	}
998 
999 	{
1000 		OSSharedPtr<OSDictionary> table;
1001 		OSSharedPtr<OSDictionary> result = IOService::resourceMatching("name", table);
1002 		assert(result);
1003 		assert(result->getRetainCount() == 1);
1004 
1005 		table = result;
1006 		assert(table->getRetainCount() == 2);
1007 		OSSharedPtr<OSDictionary> result2 = IOService::resourceMatching("name", table);
1008 		assert(result2);
1009 		assert(result2 == table);
1010 		assert(result2->getRetainCount() == 3);
1011 	}
1012 
1013 	{
1014 		OSSharedPtr<OSDictionary> table;
1015 		OSSharedPtr<OSDictionary> result = IOService::resourceMatching(name, table);
1016 		assert(result);
1017 		assert(result->getRetainCount() == 1);
1018 
1019 		table = result;
1020 		assert(table->getRetainCount() == 2);
1021 		OSSharedPtr<OSDictionary> result2 = IOService::resourceMatching(name, table);
1022 		assert(result2);
1023 		assert(result2 == table);
1024 		assert(result2->getRetainCount() == 3);
1025 	}
1026 
1027 	{
1028 		OSSharedPtr<OSDictionary> table;
1029 		OSSharedPtr<OSDictionary> result = IOService::propertyMatching(name, value, table);
1030 		assert(result);
1031 		assert(result->getRetainCount() == 1);
1032 
1033 		table = result;
1034 		assert(table->getRetainCount() == 2);
1035 		OSSharedPtr<OSDictionary> result2 = IOService::propertyMatching(name, value, table);
1036 		assert(result2);
1037 		assert(result2 == table);
1038 		assert(result2->getRetainCount() == 3);
1039 	}
1040 
1041 	{
1042 		OSSharedPtr<OSDictionary> table;
1043 		OSSharedPtr<OSDictionary> result = IOService::registryEntryIDMatching(12, table);
1044 		assert(result);
1045 		assert(result->getRetainCount() == 1);
1046 
1047 		table = result;
1048 		assert(table->getRetainCount() == 2);
1049 		OSSharedPtr<OSDictionary> result2 = IOService::registryEntryIDMatching(12, table);
1050 		assert(result2);
1051 		assert(result2 == table);
1052 		assert(result2->getRetainCount() == 3);
1053 	}
1054 	OSSafeReleaseNULL(name);
1055 	OSSafeReleaseNULL(value);
1056 }
1057 
1058 static int
OSSharedPtrTests(int)1059 OSSharedPtrTests(int)
1060 {
1061 	OSDynamicPtrCastTests();
1062 	OSConstPtrCastTests();
1063 	OSStaticPtrCastTests();
1064 	IOServiceMatchingSharedPtrTests();
1065 	return 0;
1066 }
1067 
1068 static int
IOServiceStateNotificationTests(int)1069 IOServiceStateNotificationTests(int)
1070 {
1071 	IOService * service = IOService::getSystemStateNotificationService();
1072 	OSString * str = OSString::withCString(kIOSystemStateClamshellKey);
1073 	kern_return_t kr = service->StateNotificationItemCreate(str, NULL);
1074 	assert(kIOReturnSuccess == kr);
1075 
1076 	void (^sendClam)(OSBoolean * state) = ^void (OSBoolean * state) {
1077 		OSDictionary * value;
1078 		kern_return_t kr;
1079 
1080 		value = OSDictionary::withCapacity(4);
1081 		value->setObject("value", state);
1082 		kr = IOService::getSystemStateNotificationService()->StateNotificationItemSet(str, value);
1083 		assert(kIOReturnSuccess == kr);
1084 		value->release();
1085 	};
1086 	sendClam(kOSBooleanTrue);
1087 	IOSleep(100);
1088 	sendClam(kOSBooleanFalse);
1089 	str->release();
1090 
1091 	str = OSString::withCString("test");
1092 	OSArray  * array = OSArray::withCapacity(4);
1093 	array->setObject(str);
1094 	IOStateNotificationListenerRef listenerRef;
1095 	kr = service->stateNotificationListenerAdd(array, &listenerRef, ^kern_return_t () {
1096 		IOLog("test handler\n");
1097 		kern_return_t kr;
1098 		OSDictionary * dict;
1099 		kr = service->StateNotificationItemCopy(str, &dict);
1100 		if (kIOReturnSuccess == kr) {
1101 		        OSSerialize * s = OSSerialize::withCapacity(4096);
1102 		        dict->serialize(s);
1103 		        IOLog("test handler %s\n", s->text());
1104 		        s->release();
1105 		}
1106 		return kIOReturnSuccess;
1107 	});
1108 	assert(kIOReturnSuccess == kr);
1109 
1110 	IOEventSource * es =
1111 	    IOServiceStateNotificationEventSource::serviceStateNotificationEventSource(
1112 		service, array,
1113 		^void () {
1114 		IOLog("test es handler\n");
1115 		kern_return_t kr;
1116 		OSDictionary * dict;
1117 		kr = service->StateNotificationItemCopy(str, &dict);
1118 		if (kIOReturnSuccess == kr) {
1119 		        OSSerialize * s = OSSerialize::withCapacity(4096);
1120 		        dict->serialize(s);
1121 		        IOLog("test es handler %s\n", s->text());
1122 		        s->release();
1123 		}
1124 	});
1125 	assert(es != nullptr);
1126 	IOService::getPlatform()->getWorkLoop()->addEventSource(es);
1127 	es->enable();
1128 	IOSleep(30 * 1000);
1129 	IOService::getPlatform()->getWorkLoop()->removeEventSource(es);
1130 	es->release();
1131 
1132 	return kIOReturnSuccess;
1133 }
1134 
1135 
1136 #endif  /* DEVELOPMENT || DEBUG */
1137 
1138 #ifndef __clang_analyzer__
1139 // All the scary things that this function is doing, such as the intentional
1140 // overrelease of an OSData, are hidden from the static analyzer.
1141 static int
sysctl_iokittest(__unused struct sysctl_oid * oidp,__unused void * arg1,__unused int arg2,struct sysctl_req * req)1142 sysctl_iokittest(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
1143 {
1144 	int error;
1145 	int newValue, changed;
1146 
1147 	error = sysctl_io_number(req, 0, sizeof(int), &newValue, &changed);
1148 	if (error) {
1149 		return error;
1150 	}
1151 
1152 #if DEVELOPMENT || DEBUG
1153 	if (changed && (66 == newValue)) {
1154 		IOReturn ret;
1155 		IOWorkLoop * wl = IOWorkLoop::workLoop();
1156 		IOCommandGate * cg = IOCommandGate::commandGate(wl);
1157 		ret = wl->addEventSource(cg);
1158 
1159 		struct x {
1160 			uint64_t h;
1161 			uint64_t l;
1162 		};
1163 		struct x y;
1164 
1165 		y.h = 0x1111111122222222;
1166 		y.l = 0x3333333344444444;
1167 
1168 		kprintf("ret1 %d\n", ret);
1169 		ret = cg->runActionBlock(^(){
1170 			printf("hello %d 0x%qx\n", wl->inGate(), y.h);
1171 			return 99;
1172 		});
1173 		kprintf("ret %d\n", ret);
1174 	}
1175 
1176 	if (changed && (999 == newValue)) {
1177 		OSData * data = OSData::withCapacity(16);
1178 		data->release();
1179 		data->release();
1180 	}
1181 
1182 	if (changed && (newValue >= 6666) && (newValue <= 6669)) {
1183 		OSIterator * iter;
1184 		IOService  * service;
1185 
1186 		service = NULL;
1187 		iter = IOService::getMatchingServices(IOService::nameMatching("XHC1"));
1188 		if (iter && (service = (IOService *) iter->getNextObject())) {
1189 			if (newValue == 6666) {
1190 				IOLog("terminating 0x%qx\n", service->getRegistryEntryID());
1191 				service->terminate();
1192 			} else if (newValue == 6667) {
1193 				IOLog("register 0x%qx\n", service->getRegistryEntryID());
1194 				service->registerService();
1195 			}
1196 		}
1197 		OSSafeReleaseNULL(iter);
1198 		if (service) {
1199 			return 0;
1200 		}
1201 	}
1202 
1203 
1204 	if (changed && (555 == newValue)) {
1205 		IOServiceStateNotificationTests(newValue);
1206 	}
1207 
1208 	if (changed && newValue) {
1209 		error = IOWorkLoopTest(newValue);
1210 		assert(KERN_SUCCESS == error);
1211 		error = IOServiceTest(newValue);
1212 		assert(KERN_SUCCESS == error);
1213 		error = OSCollectionTest(newValue);
1214 		assert(KERN_SUCCESS == error);
1215 		error = OSCollectionIteratorTests(newValue);
1216 		assert(KERN_SUCCESS == error);
1217 		error = OSAllocationTests(newValue);
1218 		assert(KERN_SUCCESS == error);
1219 		error = OSDataAllocationTests(newValue);
1220 		assert(KERN_SUCCESS == error);
1221 		error = OSBoundedArrayTests(newValue);
1222 		assert(KERN_SUCCESS == error);
1223 		error = OSBoundedArrayRefTests(newValue);
1224 		assert(KERN_SUCCESS == error);
1225 		error = OSBoundedPtrTests(newValue);
1226 		assert(KERN_SUCCESS == error);
1227 		error = IOMemoryDescriptorTest(newValue);
1228 		assert(KERN_SUCCESS == error);
1229 		error = OSSharedPtrTests(newValue);
1230 		assert(KERN_SUCCESS == error);
1231 		error = IOSharedDataQueue_44636964(newValue);
1232 		assert(KERN_SUCCESS == error);
1233 		error = IOUserNotificationTests(newValue);
1234 		assert(KERN_SUCCESS == error);
1235 	}
1236 #endif  /* DEVELOPMENT || DEBUG */
1237 
1238 	return error;
1239 }
1240 
1241 SYSCTL_PROC(_kern, OID_AUTO, iokittest,
1242     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
1243     NULL, 0, sysctl_iokittest, "I", "");
1244 #endif // __clang_analyzer__
1245 
1246 #if DEVELOPMENT || DEBUG
1247 
1248 /*
1249  * A simple wrapper around an IOService. This terminates the IOService in free().
1250  */
1251 class TestIOServiceHandle : public OSObject
1252 {
1253 	OSDeclareDefaultStructors(TestIOServiceHandle);
1254 public:
1255 	static TestIOServiceHandle * withService(IOService * service);
1256 
1257 private:
1258 	bool initWithService(IOService * service);
1259 	virtual void free() APPLE_KEXT_OVERRIDE;
1260 
1261 	IOService * fService;
1262 };
1263 
1264 OSDefineMetaClassAndStructors(TestIOServiceHandle, OSObject);
1265 
1266 TestIOServiceHandle *
withService(IOService * service)1267 TestIOServiceHandle::withService(IOService * service)
1268 {
1269 	TestIOServiceHandle * handle = new TestIOServiceHandle;
1270 	if (handle && !handle->initWithService(service)) {
1271 		return NULL;
1272 	}
1273 	return handle;
1274 }
1275 
1276 bool
initWithService(IOService * service)1277 TestIOServiceHandle::initWithService(IOService * service)
1278 {
1279 	fService = service;
1280 	fService->retain();
1281 	return true;
1282 }
1283 
1284 void
free()1285 TestIOServiceHandle::free()
1286 {
1287 	if (fService) {
1288 		fService->terminate();
1289 		OSSafeReleaseNULL(fService);
1290 	}
1291 }
1292 
1293 /*
1294  * Set up test IOServices. See the available services in xnu/iokit/Tests/TestServices.
1295  *
1296  * xnu darwintests use this sysctl to make these test services available. A send right is pushed
1297  * to the task that called the sysctl, which when deallocated removes the service. This ensures
1298  * that the registry isn't polluted by misbehaving tests.
1299  *
1300  * Since this sysctl allows callers to instantiate arbitrary classes based on their class name,
1301  * this can be a security concern. Tests that call this sysctl need the
1302  * kIOServiceTestServiceManagementEntitlementKey entitlement.
1303  */
1304 static int
sysctl_iokit_test_service_setup(struct sysctl_oid * oidp,__unused void * arg1,__unused int arg2,struct sysctl_req * req)1305 sysctl_iokit_test_service_setup(struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
1306 {
1307 	char classname[128] = {0};
1308 	IOService * service; // must not release
1309 	OSObject * obj = NULL; // must release
1310 	IOService * provider = NULL; // must not release
1311 	TestIOServiceHandle * handle = NULL; // must release
1312 	mach_port_name_t name __unused;
1313 	int error;
1314 
1315 	if (!IOTaskHasEntitlement(current_task(), kIOServiceTestServiceManagementEntitlementKey)) {
1316 		error = EPERM;
1317 		goto finish;
1318 	}
1319 
1320 	error = sysctl_handle_string(oidp, classname, sizeof(classname), req);
1321 	if (error != 0) {
1322 		goto finish;
1323 	}
1324 
1325 	/*
1326 	 * All test services currently attach to IOResources.
1327 	 */
1328 	provider = IOService::getResourceService();
1329 	if (!provider) {
1330 		IOLog("Failed to find IOResources\n");
1331 		error = ENOENT;
1332 		goto finish;
1333 	}
1334 
1335 	obj = OSMetaClass::allocClassWithName(classname);
1336 	if (!obj) {
1337 		IOLog("Failed to alloc class %s\n", classname);
1338 		error = ENOENT;
1339 		goto finish;
1340 	}
1341 
1342 	service = OSDynamicCast(IOService, obj);
1343 
1344 	if (!service) {
1345 		IOLog("Instance of class %s is not an IOService\n", classname);
1346 		error = EINVAL;
1347 		goto finish;
1348 	}
1349 
1350 	if (!service->init()) {
1351 		IOLog("Failed to initialize %s\n", classname);
1352 		error = EINVAL;
1353 		goto finish;
1354 	}
1355 
1356 	if (!service->attach(provider)) {
1357 		IOLog("Failed to attach %s\n", classname);
1358 		error = EINVAL;
1359 		goto finish;
1360 	}
1361 
1362 	if (!service->start(provider)) {
1363 		IOLog("Failed to start %s\n", classname);
1364 		error = EINVAL;
1365 		goto finish;
1366 	}
1367 
1368 	handle = TestIOServiceHandle::withService(service);
1369 	if (!handle) {
1370 		IOLog("Failed to create service handle\n");
1371 		error = ENOMEM;
1372 		goto finish;
1373 	}
1374 	name = iokit_make_send_right(current_task(), handle, IKOT_IOKIT_OBJECT);
1375 
1376 	error = 0;
1377 
1378 finish:
1379 
1380 	OSSafeReleaseNULL(obj);
1381 	OSSafeReleaseNULL(handle);
1382 	return error;
1383 }
1384 
1385 
1386 SYSCTL_PROC(_kern, OID_AUTO, iokit_test_service_setup,
1387     CTLTYPE_STRING | CTLFLAG_WR | CTLFLAG_KERN | CTLFLAG_LOCKED,
1388     NULL, 0, sysctl_iokit_test_service_setup, "-", "");
1389 
1390 #endif /* DEVELOPMENT || DEBUG */
1391 
1392 
1393 static __unused void
CastCompileTest(OSObject * obj)1394 CastCompileTest(OSObject *obj)
1395 {
1396 	OSDynamicCast(IOService, obj)->terminate();
1397 	OSRequiredCast(IOService, obj)->terminate();
1398 }
1399