2 * io_catalog_send_data.m
4 * A regression test to build an IORegistry entry with mismatching
5 * IOService and IOUserClientClass via IOCatalogueSendData, to verify
6 * if exploit risk still exists in IOCatalogueSendData.
9 #include <darwintest.h>
11 #include <Foundation/Foundation.h>
12 #include <IOKit/IOCFSerialize.h>
13 #include <IOKit/IOKitLib.h>
15 #define kIOClassKey @"IOClass"
16 #define kIOProviderClassKey @"IOProviderClass"
17 #define kIOMatchCategoryKey @"IOMatchCategory"
18 #define kIOUserClientClassKey @"IOUserClientClass"
19 #define vIOProviderClassValue @"IOResources"
21 T_GLOBAL_META(T_META_NAMESPACE("xnu.iokit"),
22 T_META_RUN_CONCURRENTLY(true));
25 build_ioregistry_by_catalog_send_data(const char *match_name,
26 const char *userclient_name, const char *service_name)
30 NSArray *rootCatalogueArray = @[@{
31 kIOProviderClassKey: vIOProviderClassValue,
32 kIOClassKey: @(service_name),
33 kIOUserClientClassKey: @(userclient_name),
34 kIOMatchCategoryKey: @(match_name)
37 CFDataRef cfData = IOCFSerialize((__bridge CFTypeRef)rootCatalogueArray,
38 kIOCFSerializeToBinary);
40 kret = IOCatalogueSendData(MACH_PORT_NULL, 1, CFDataGetBytePtr(cfData),
41 CFDataGetLength(cfData));
51 test_open_ioregistry(const char *match_name, const char *service_name,
55 bool ioreg_found = false;
56 CFStringRef cfstrMatchName = NULL;
57 io_connect_t conn = IO_OBJECT_NULL;
58 io_iterator_t iter = IO_OBJECT_NULL, obj = IO_OBJECT_NULL;
59 CFMutableDictionaryRef service_info = NULL, properties = NULL;
61 service_info = IOServiceMatching(service_name);
62 kret = IOServiceGetMatchingServices(kIOMasterPortDefault, service_info, &iter);
63 T_QUIET; T_ASSERT_MACH_SUCCESS(kret, "IOServiceGetMatchingServices");
64 cfstrMatchName = CFStringCreateWithCString(kCFAllocatorDefault,
65 match_name, kCFStringEncodingUTF8);
67 while (obj = IOIteratorNext(iter)) {
68 kret = IORegistryEntryCreateCFProperties(obj, &properties,
69 kCFAllocatorDefault, kNilOptions);
70 if (kret != KERN_SUCCESS) {
71 T_LOG("IORegistryEntryCreateCFProperties fails, 0x%08X",
77 CFStringRef value = CFDictionaryGetValue(properties, CFSTR("IOMatchCategory"));
78 if (value && CFGetTypeID(value) == CFStringGetTypeID() &&
79 CFEqual(value, cfstrMatchName)) {
90 T_LOG("try to exploit by opening io service, possibly panic?");
91 IOServiceOpen(obj, mach_task_self(), 0, &conn);
99 CFRelease(cfstrMatchName);
103 CFRelease(properties);
106 if (iter != IO_OBJECT_NULL) {
107 IOObjectRelease(iter);
110 if (conn != IO_OBJECT_NULL) {
111 IOServiceClose(conn);
117 T_DECL(io_catalog_send_data_test, "regression test to build an IORegistry entry"
118 " with mismatching IOService and IOUserClientClass by IOCatalogueSendData, "
119 "to verify if exploit risk still exists in IOCatalogueSendData for "
120 "potential DoS - <rdar://problem/31558871>")
124 kret = build_ioregistry_by_catalog_send_data("fooBar",
125 "IOSurfaceRootUserClient", "IOReportHub");
126 #if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
127 /* this trick to build an entry by io_catalog_send_data should fail */
128 T_EXPECT_EQ(kret, kIOReturnNotPrivileged, "build an entry with"
129 " mismatch IOService and IOUserClientClass by IOCatalogueSendData "
130 "should fail as kIOReturnNotPrivileged");
132 T_EXPECT_EQ(kret, KERN_SUCCESS, "IOCatalogueSendData should return success with kextd");
134 T_EXPECT_FALSE(test_open_ioregistry("fooBar", "IOReportHub", false),
135 "Mismatched entry built by IOCatalogueSendData should not be opened");