1*e3723e1fSApple OSS Distributions// Copyright (c) 2019-2020 Apple Inc. 2*e3723e1fSApple OSS Distributions 3*e3723e1fSApple OSS Distributions#include <darwintest.h> 4*e3723e1fSApple OSS Distributions#include <sys/sysctl.h> 5*e3723e1fSApple OSS Distributions 6*e3723e1fSApple OSS Distributions#include <Foundation/Foundation.h> 7*e3723e1fSApple OSS Distributions#include <IOKit/IOCFSerialize.h> 8*e3723e1fSApple OSS Distributions#include <IOKit/IOKitLib.h> 9*e3723e1fSApple OSS Distributions 10*e3723e1fSApple OSS DistributionsT_GLOBAL_META(T_META_NAMESPACE("xnu.iokit"), 11*e3723e1fSApple OSS Distributions T_META_RUN_CONCURRENTLY(true)); 12*e3723e1fSApple OSS Distributions 13*e3723e1fSApple OSS Distributionsstatic kern_return_t 14*e3723e1fSApple OSS Distributionsbuild_ioregistry_by_catalog_send_data(const char *match_name, 15*e3723e1fSApple OSS Distributions const char *userclient_name, const char *service_name) 16*e3723e1fSApple OSS Distributions{ 17*e3723e1fSApple OSS Distributions NSArray *rootCatalogueArray = @[@{ 18*e3723e1fSApple OSS Distributions @kIOProviderClassKey: @kIOResourcesClass, 19*e3723e1fSApple OSS Distributions @kIOClassKey: (NSString * __nonnull)@(service_name), 20*e3723e1fSApple OSS Distributions @kIOUserClientClassKey: (NSString * __nonnull)@(userclient_name), 21*e3723e1fSApple OSS Distributions @kIOMatchCategoryKey: (NSString * __nonnull)@(match_name) 22*e3723e1fSApple OSS Distributions }]; 23*e3723e1fSApple OSS Distributions 24*e3723e1fSApple OSS Distributions CFDataRef cfData = IOCFSerialize((__bridge CFTypeRef)rootCatalogueArray, 25*e3723e1fSApple OSS Distributions kIOCFSerializeToBinary); 26*e3723e1fSApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(cfData, "IOCFSerialize root catalogue array"); 27*e3723e1fSApple OSS Distributions kern_return_t kret = IOCatalogueSendData(MACH_PORT_NULL, 1, 28*e3723e1fSApple OSS Distributions (const char *)CFDataGetBytePtr(cfData), 29*e3723e1fSApple OSS Distributions (uint32_t)CFDataGetLength(cfData)); 30*e3723e1fSApple OSS Distributions CFRelease(cfData); 31*e3723e1fSApple OSS Distributions return kret; 32*e3723e1fSApple OSS Distributions} 33*e3723e1fSApple OSS Distributions 34*e3723e1fSApple OSS Distributionsstatic bool 35*e3723e1fSApple OSS Distributionstest_open_ioregistry(const char *match_name, const char *service_name, 36*e3723e1fSApple OSS Distributions bool exploit) 37*e3723e1fSApple OSS Distributions{ 38*e3723e1fSApple OSS Distributions kern_return_t kret; 39*e3723e1fSApple OSS Distributions bool ioreg_found = false; 40*e3723e1fSApple OSS Distributions CFStringRef cfstrMatchName = NULL; 41*e3723e1fSApple OSS Distributions io_connect_t conn = IO_OBJECT_NULL; 42*e3723e1fSApple OSS Distributions io_iterator_t iter = IO_OBJECT_NULL, obj = IO_OBJECT_NULL; 43*e3723e1fSApple OSS Distributions CFMutableDictionaryRef service_info = NULL, properties = NULL; 44*e3723e1fSApple OSS Distributions 45*e3723e1fSApple OSS Distributions service_info = IOServiceMatching(service_name); 46*e3723e1fSApple OSS Distributions kret = IOServiceGetMatchingServices(kIOMasterPortDefault, service_info, &iter); 47*e3723e1fSApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(kret, "IOServiceGetMatchingServices"); 48*e3723e1fSApple OSS Distributions cfstrMatchName = CFStringCreateWithCString(kCFAllocatorDefault, 49*e3723e1fSApple OSS Distributions match_name, kCFStringEncodingUTF8); 50*e3723e1fSApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(cfstrMatchName, 51*e3723e1fSApple OSS Distributions "created CFString from match name"); 52*e3723e1fSApple OSS Distributions 53*e3723e1fSApple OSS Distributions while ((obj = IOIteratorNext(iter)) != 0) { 54*e3723e1fSApple OSS Distributions kret = IORegistryEntryCreateCFProperties(obj, &properties, 55*e3723e1fSApple OSS Distributions kCFAllocatorDefault, kNilOptions); 56*e3723e1fSApple OSS Distributions if (kret != KERN_SUCCESS) { 57*e3723e1fSApple OSS Distributions T_LOG("IORegistryEntryCreateCFProperties fails, 0x%08X", 58*e3723e1fSApple OSS Distributions (uint32_t)kret); 59*e3723e1fSApple OSS Distributions IOObjectRelease(obj); 60*e3723e1fSApple OSS Distributions continue; 61*e3723e1fSApple OSS Distributions } 62*e3723e1fSApple OSS Distributions 63*e3723e1fSApple OSS Distributions CFStringRef value = CFDictionaryGetValue(properties, CFSTR("IOMatchCategory")); 64*e3723e1fSApple OSS Distributions if (value && CFGetTypeID(value) == CFStringGetTypeID() && 65*e3723e1fSApple OSS Distributions CFEqual(value, cfstrMatchName)) { 66*e3723e1fSApple OSS Distributions ioreg_found = true; 67*e3723e1fSApple OSS Distributions } else { 68*e3723e1fSApple OSS Distributions IOObjectRelease(obj); 69*e3723e1fSApple OSS Distributions continue; 70*e3723e1fSApple OSS Distributions } 71*e3723e1fSApple OSS Distributions 72*e3723e1fSApple OSS Distributions if (!exploit) { 73*e3723e1fSApple OSS Distributions IOObjectRelease(obj); 74*e3723e1fSApple OSS Distributions break; 75*e3723e1fSApple OSS Distributions } 76*e3723e1fSApple OSS Distributions 77*e3723e1fSApple OSS Distributions T_LOG("try to exploit by opening service, possibly panic..."); 78*e3723e1fSApple OSS Distributions IOServiceOpen(obj, mach_task_self(), 0, &conn); 79*e3723e1fSApple OSS Distributions IOObjectRelease(obj); 80*e3723e1fSApple OSS Distributions 81*e3723e1fSApple OSS Distributions break; 82*e3723e1fSApple OSS Distributions } 83*e3723e1fSApple OSS Distributions 84*e3723e1fSApple OSS Distributions CFRelease(cfstrMatchName); 85*e3723e1fSApple OSS Distributions 86*e3723e1fSApple OSS Distributions if (properties) { 87*e3723e1fSApple OSS Distributions CFRelease(properties); 88*e3723e1fSApple OSS Distributions } 89*e3723e1fSApple OSS Distributions 90*e3723e1fSApple OSS Distributions if (iter != IO_OBJECT_NULL) { 91*e3723e1fSApple OSS Distributions IOObjectRelease(iter); 92*e3723e1fSApple OSS Distributions } 93*e3723e1fSApple OSS Distributions 94*e3723e1fSApple OSS Distributions if (conn != IO_OBJECT_NULL) { 95*e3723e1fSApple OSS Distributions IOServiceClose(conn); 96*e3723e1fSApple OSS Distributions } 97*e3723e1fSApple OSS Distributions 98*e3723e1fSApple OSS Distributions return ioreg_found; 99*e3723e1fSApple OSS Distributions} 100*e3723e1fSApple OSS Distributions 101*e3723e1fSApple OSS DistributionsT_DECL(io_catalog_send_data_test, 102*e3723e1fSApple OSS Distributions "build an IORegistry entry with mismatching IOService and " 103*e3723e1fSApple OSS Distributions "IOUserClientClass by IOCatalogueSendData to check for DoS in " 104*e3723e1fSApple OSS Distributions "IOCatalogueSendData", T_META_TAG_VM_PREFERRED) 105*e3723e1fSApple OSS Distributions{ 106*e3723e1fSApple OSS Distributions kern_return_t kret = build_ioregistry_by_catalog_send_data("fooBar", 107*e3723e1fSApple OSS Distributions "IOSurfaceRootUserClient", "IOReportHub"); 108*e3723e1fSApple OSS Distributions#if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) 109*e3723e1fSApple OSS Distributions int development = 0; 110*e3723e1fSApple OSS Distributions size_t development_size = sizeof(development); 111*e3723e1fSApple OSS Distributions 112*e3723e1fSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(sysctlbyname("kern.development", &development, 113*e3723e1fSApple OSS Distributions &development_size, NULL, 0), "sysctl kern.development"); 114*e3723e1fSApple OSS Distributions 115*e3723e1fSApple OSS Distributions if (development) { 116*e3723e1fSApple OSS Distributions T_EXPECT_MACH_SUCCESS(kret, "IOCatalogueSendData should " 117*e3723e1fSApple OSS Distributions "return success with development kernel"); 118*e3723e1fSApple OSS Distributions } else { 119*e3723e1fSApple OSS Distributions /* this trick to build an entry by io_catalog_send_data should fail */ 120*e3723e1fSApple OSS Distributions T_EXPECT_EQ(kret, kIOReturnNotPrivileged, "build an entry with" 121*e3723e1fSApple OSS Distributions " mismatch IOService and IOUserClientClass by IOCatalogueSendData " 122*e3723e1fSApple OSS Distributions "should fail as kIOReturnNotPrivileged in none-dev kernel without kernelmanagerd"); 123*e3723e1fSApple OSS Distributions } 124*e3723e1fSApple OSS Distributions#else 125*e3723e1fSApple OSS Distributions T_EXPECT_MACH_SUCCESS(kret, 126*e3723e1fSApple OSS Distributions "IOCatalogueSendData should return success with kernelmanagerd"); 127*e3723e1fSApple OSS Distributions#endif /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */ 128*e3723e1fSApple OSS Distributions T_EXPECT_FALSE(test_open_ioregistry("fooBar", "IOReportHub", false), 129*e3723e1fSApple OSS Distributions "mismatched entry built by IOCatalogueSendData should not be opened"); 130*e3723e1fSApple OSS Distributions} 131