X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/c6bf4f310a33a9262d455ea4d3f0630b1255e3fe..refs/heads/master:/iokit/Kernel/IOUserClient.cpp diff --git a/iokit/Kernel/IOUserClient.cpp b/iokit/Kernel/IOUserClient.cpp index 9b3cef8ce..6d1edda91 100644 --- a/iokit/Kernel/IOUserClient.cpp +++ b/iokit/Kernel/IOUserClient.cpp @@ -28,6 +28,7 @@ #include +#include #include #include #include @@ -173,35 +174,37 @@ public: }; #define super OSObject -OSDefineMetaClassAndStructors(IOMachPort, OSObject) +OSDefineMetaClassAndStructorsWithZone(IOMachPort, OSObject, ZC_ZFREE_CLEARMEM) static IOLock * gIOObjectPortLock; IOLock * gIOUserServerLock; +SECURITY_READ_ONLY_LATE(const struct io_filter_callbacks *) gIOUCFilterCallbacks; + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ SLIST_HEAD(IOMachPortHashList, IOMachPort); -#if CONFIG_EMBEDDED -#define PORT_HASH_SIZE 256 -#else +#if defined(XNU_TARGET_OS_OSX) #define PORT_HASH_SIZE 4096 -#endif /* CONFIG_EMBEDDED */ +#else /* defined(!XNU_TARGET_OS_OSX) */ +#define PORT_HASH_SIZE 256 +#endif /* !defined(!XNU_TARGET_OS_OSX) */ -IOMachPortHashList ports[PORT_HASH_SIZE]; +IOMachPortHashList gIOMachPortHash[PORT_HASH_SIZE]; void IOMachPortInitialize(void) { for (size_t i = 0; i < PORT_HASH_SIZE; i++) { - SLIST_INIT(&ports[i]); + SLIST_INIT(&gIOMachPortHash[i]); } } IOMachPortHashList* IOMachPort::bucketForObject(OSObject *obj, ipc_kobject_type_t type ) { - return &ports[os_hash_kernel_pointer(obj) % PORT_HASH_SIZE]; + return &gIOMachPortHash[os_hash_kernel_pointer(obj) % PORT_HASH_SIZE]; } IOMachPort* @@ -409,6 +412,23 @@ IOMachPort::free( void ) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +static bool +IOTaskRegistryCompatibility(task_t task) +{ + return false; +} + +static void +IOTaskRegistryCompatibilityMatching(task_t task, OSDictionary * matching) +{ + if (!IOTaskRegistryCompatibility(task)) { + return; + } + matching->setObject(gIOCompatibilityMatchKey, kOSBooleanTrue); +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + class IOUserIterator : public OSIterator { OSDeclareDefaultStructors(IOUserIterator); @@ -548,7 +568,35 @@ extern "C" { // functions called from osfmk/device/iokit_rpc.c void -iokit_add_reference( io_object_t obj, ipc_kobject_type_t type ) +iokit_port_object_description(io_object_t obj, kobject_description_t desc) +{ + IORegistryEntry * regEntry; + IOUserNotification * __unused noti; + _IOServiceNotifier * __unused serviceNoti; + OSSerialize * __unused s; + + if ((regEntry = OSDynamicCast(IORegistryEntry, obj))) { + snprintf(desc, KOBJECT_DESCRIPTION_LENGTH, "%s(0x%qx)", obj->getMetaClass()->getClassName(), regEntry->getRegistryEntryID()); +#if DEVELOPMENT || DEBUG + } else if ((noti = OSDynamicCast(IOUserNotification, obj)) + && ((serviceNoti = OSDynamicCast(_IOServiceNotifier, noti->holdNotify)))) { + s = OSSerialize::withCapacity((unsigned int) page_size); + if (s && serviceNoti->matching->serialize(s)) { + snprintf(desc, KOBJECT_DESCRIPTION_LENGTH, "%s(%s)", obj->getMetaClass()->getClassName(), s->text()); + } + OSSafeReleaseNULL(s); +#endif /* DEVELOPMENT || DEBUG */ + } else { + snprintf(desc, KOBJECT_DESCRIPTION_LENGTH, "%s", obj->getMetaClass()->getClassName()); + } +} + +// FIXME: Implementation of these functions are hidden from the static analyzer. +// As for now, the analyzer doesn't consistently support wrapper functions +// for retain and release. +#ifndef __clang_analyzer__ +void +iokit_add_reference( io_object_t obj, natural_t type ) { IOUserClient * uc; @@ -571,6 +619,7 @@ iokit_remove_reference( io_object_t obj ) obj->release(); } } +#endif // __clang_analyzer__ void iokit_remove_connect_reference( io_object_t obj ) @@ -652,24 +701,33 @@ iokit_client_died( io_object_t obj, ipc_port_t /* port */, IOUserClient * client; IOMemoryMap * map; IOUserNotification * notify; + IOUserServerCheckInToken * token; if (!IOMachPort::noMoreSendersForObject( obj, type, mscount )) { return kIOReturnNotReady; } - if (IKOT_IOKIT_CONNECT == type) { + switch (type) { + case IKOT_IOKIT_CONNECT: if ((client = OSDynamicCast( IOUserClient, obj ))) { IOStatisticsClientCall(); - IOLockLock(client->lock); + IORWLockWrite(client->lock); client->clientDied(); - IOLockUnlock(client->lock); + IORWLockUnlock(client->lock); } - } else if (IKOT_IOKIT_OBJECT == type) { + break; + case IKOT_IOKIT_OBJECT: if ((map = OSDynamicCast( IOMemoryMap, obj ))) { map->taskDied(); } else if ((notify = OSDynamicCast( IOUserNotification, obj ))) { notify->setNotification( NULL ); } + break; + case IKOT_IOKIT_IDENT: + if ((token = OSDynamicCast( IOUserServerCheckInToken, obj ))) { + IOUserServerCheckInToken::notifyNoSenders( token ); + } + break; } return kIOReturnSuccess; @@ -690,7 +748,7 @@ class IOServiceUserNotification : public IOUserNotification enum { kMaxOutstanding = 1024 }; PingMsg * pingMsg; - vm_size_t msgSize; + mach_msg_size_t msgSize; OSArray * newSet; bool armed; bool ipcLogged; @@ -723,7 +781,7 @@ class IOServiceMessageUserNotification : public IOUserNotification }; PingMsg * pingMsg; - vm_size_t msgSize; + mach_msg_size_t msgSize; uint8_t clientIs64; int owningPID; bool ipcLogged; @@ -732,7 +790,7 @@ public: virtual bool init( mach_port_t port, natural_t type, void * reference, vm_size_t referenceSize, - vm_size_t extraSize, + mach_msg_size_t extraSize, bool clientIs64 ); virtual void free() APPLE_KEXT_OVERRIDE; @@ -828,7 +886,8 @@ IOServiceUserNotification::init( mach_port_t port, natural_t type, return false; } - msgSize = sizeof(PingMsg) - sizeof(OSAsyncReference64) + referenceSize; + msgSize = (mach_msg_size_t) (sizeof(PingMsg) - sizeof(OSAsyncReference64) + referenceSize); + pingMsg = (PingMsg *) IOMalloc( msgSize); if (!pingMsg) { return false; @@ -976,7 +1035,7 @@ OSDefineMetaClassAndStructors(IOServiceMessageUserNotification, IOUserNotificati bool IOServiceMessageUserNotification::init( mach_port_t port, natural_t type, - void * reference, vm_size_t referenceSize, vm_size_t extraSize, + void * reference, vm_size_t referenceSize, mach_msg_size_t extraSize, bool client64 ) { if (!super::init()) { @@ -992,7 +1051,7 @@ IOServiceMessageUserNotification::init( mach_port_t port, natural_t type, owningPID = proc_selfpid(); extraSize += sizeof(IOServiceInterestContent64); - msgSize = sizeof(PingMsg) - sizeof(OSAsyncReference64) + referenceSize; + msgSize = (mach_msg_size_t) (sizeof(PingMsg) - sizeof(OSAsyncReference64) + referenceSize); pingMsg = (PingMsg *) IOMalloc( msgSize); if (!pingMsg) { return false; @@ -1067,7 +1126,7 @@ IOServiceMessageUserNotification::handler( void * ref, void * allocMsg; kern_return_t kr; vm_size_t argSize; - vm_size_t thisMsgSize; + mach_msg_size_t thisMsgSize; ipc_port_t thisPort, providerPort; struct PingMsg * thisMsg; IOServiceInterestContent64 * data; @@ -1097,10 +1156,9 @@ IOServiceMessageUserNotification::handler( void * ref, type |= ((argSize & kIOKitNoticationMsgSizeMask) << kIOKitNoticationTypeSizeAdjShift); argSize = (argSize + kIOKitNoticationMsgSizeMask) & ~kIOKitNoticationMsgSizeMask; - thisMsgSize = msgSize - + sizeof(IOServiceInterestContent64) - - sizeof(data->messageArgument) - + argSize; + if (os_add3_overflow(msgSize, sizeof(IOServiceInterestContent64) - sizeof(data->messageArgument), argSize, &thisMsgSize)) { + return kIOReturnBadArgument; + } if (thisMsgSize > sizeof(stackMsg)) { allocMsg = IOMalloc(thisMsgSize); @@ -1187,17 +1245,32 @@ IOUserClient::initialize( void ) gIOUserClientOwnersLock = IOLockAlloc(); gIOUserServerLock = IOLockAlloc(); assert(gIOObjectPortLock && gIOUserClientOwnersLock); + +#if IOTRACKING + IOTrackingQueueCollectUser(IOUserIterator::gMetaClass.getTracking()); + IOTrackingQueueCollectUser(IOServiceMessageUserNotification::gMetaClass.getTracking()); + IOTrackingQueueCollectUser(IOServiceUserNotification::gMetaClass.getTracking()); + IOTrackingQueueCollectUser(IOUserClient::gMetaClass.getTracking()); + IOTrackingQueueCollectUser(IOMachPort::gMetaClass.getTracking()); +#endif /* IOTRACKING */ } void +#if __LP64__ +__attribute__((__noreturn__)) +#endif IOUserClient::setAsyncReference(OSAsyncReference asyncRef, mach_port_t wakePort, void *callback, void *refcon) { +#if __LP64__ + panic("setAsyncReference not valid for 64b"); +#else asyncRef[kIOAsyncReservedIndex] = ((uintptr_t) wakePort) | (kIOUCAsync0Flags & asyncRef[kIOAsyncReservedIndex]); asyncRef[kIOAsyncCalloutFuncIndex] = (uintptr_t) callback; asyncRef[kIOAsyncCalloutRefconIndex] = (uintptr_t) refcon; +#endif } void @@ -1382,24 +1455,20 @@ IOUserClient::clientHasPrivilege( void * securityToken, return kr; } +#define MAX_ENTITLEMENTS_LEN (128 * 1024) OSDictionary * IOUserClient::copyClientEntitlements(task_t task) { -#define MAX_ENTITLEMENTS_LEN (128 * 1024) - proc_t p = NULL; pid_t pid = 0; size_t len = 0; void *entitlements_blob = NULL; - char *entitlements_data = NULL; - OSObject *entitlements_obj = NULL; OSDictionary *entitlements = NULL; - OSString *errorString = NULL; p = (proc_t)get_bsdtask_info(task); if (p == NULL) { - goto fail; + return NULL; } pid = proc_pid(p); @@ -1410,8 +1479,18 @@ IOUserClient::copyClientEntitlements(task_t task) } if (cs_entitlements_blob_get(p, &entitlements_blob, &len) != 0) { - goto fail; + return NULL; } + return IOUserClient::copyEntitlementsFromBlob(entitlements_blob, len); +} + +OSDictionary * +IOUserClient::copyEntitlementsFromBlob(void *entitlements_blob, size_t len) +{ + char *entitlements_data = NULL; + OSObject *entitlements_obj = NULL; + OSString *errorString = NULL; + OSDictionary *entitlements = NULL; if (len <= offsetof(CS_GenericBlob, data)) { goto fail; @@ -1423,8 +1502,8 @@ IOUserClient::copyClientEntitlements(task_t task) */ len -= offsetof(CS_GenericBlob, data); if (len > MAX_ENTITLEMENTS_LEN) { - IOLog("failed to parse entitlements for %s[%u]: %lu bytes of entitlements exceeds maximum of %u\n", - proc_best_name(p), pid, len, MAX_ENTITLEMENTS_LEN); + IOLog("failed to parse entitlements: %lu bytes of entitlements exceeds maximum of %u\n", + len, MAX_ENTITLEMENTS_LEN); goto fail; } @@ -1442,8 +1521,7 @@ IOUserClient::copyClientEntitlements(task_t task) entitlements_obj = OSUnserializeXML(entitlements_data, len + 1, &errorString); if (errorString != NULL) { - IOLog("failed to parse entitlements for %s[%u]: %s\n", - proc_best_name(p), pid, errorString->getCStringNoCopy()); + IOLog("failed to parse entitlements: %s\n", errorString->getCStringNoCopy()); goto fail; } if (entitlements_obj == NULL) { @@ -1469,6 +1547,18 @@ fail: return entitlements; } +OSDictionary * +IOUserClient::copyClientEntitlementsVnode(vnode_t vnode, off_t offset) +{ + size_t len = 0; + void *entitlements_blob = NULL; + + if (cs_entitlements_blob_get_vnode(vnode, offset, &entitlements_blob, &len) != 0) { + return NULL; + } + return IOUserClient::copyEntitlementsFromBlob(entitlements_blob, len); +} + OSObject * IOUserClient::copyClientEntitlement( task_t task, const char * entitlement ) @@ -1491,6 +1581,30 @@ IOUserClient::copyClientEntitlement( task_t task, return value; } +OSObject * +IOUserClient::copyClientEntitlementVnode( + struct vnode *vnode, + off_t offset, + const char *entitlement) +{ + OSDictionary *entitlements; + OSObject *value; + + entitlements = copyClientEntitlementsVnode(vnode, offset); + if (entitlements == NULL) { + return NULL; + } + + /* Fetch the entitlement value from the dictionary. */ + value = entitlements->getObject(entitlement); + if (value != NULL) { + value->retain(); + } + + entitlements->release(); + return value; +} + bool IOUserClient::init() { @@ -1541,7 +1655,7 @@ bool IOUserClient::reserve() { if (!reserved) { - reserved = IONew(ExpansionData, 1); + reserved = IONewZero(ExpansionData, 1); if (!reserved) { return false; } @@ -1728,6 +1842,44 @@ iokit_task_terminate(task_t task) return KERN_SUCCESS; } +struct IOUCFilterPolicy { + task_t task; + io_filter_policy_t filterPolicy; + IOUCFilterPolicy * next; +}; + +io_filter_policy_t +IOUserClient::filterForTask(task_t task, io_filter_policy_t addFilterPolicy) +{ + IOUCFilterPolicy * elem; + io_filter_policy_t filterPolicy; + + filterPolicy = 0; + IOLockLock(filterLock); + + for (elem = reserved->filterPolicies; elem && (elem->task != task); elem = elem->next) { + } + + if (elem) { + if (addFilterPolicy) { + assert(addFilterPolicy == elem->filterPolicy); + } + filterPolicy = elem->filterPolicy; + } else if (addFilterPolicy) { + elem = IONewZero(IOUCFilterPolicy, 1); + if (elem) { + elem->task = task; + elem->filterPolicy = addFilterPolicy; + elem->next = reserved->filterPolicies; + reserved->filterPolicies = elem; + filterPolicy = addFilterPolicy; + } + } + + IOLockUnlock(filterLock); + return filterPolicy; +} + void IOUserClient::free() { @@ -1735,7 +1887,10 @@ IOUserClient::free() mappings->release(); } if (lock) { - IOLockFree(lock); + IORWLockFree(lock); + } + if (filterLock) { + IOLockFree(filterLock); } IOStatisticsUnregisterCounter(); @@ -1744,6 +1899,15 @@ IOUserClient::free() assert(!owners.prev); if (reserved) { + IOUCFilterPolicy * elem; + IOUCFilterPolicy * nextElem; + for (elem = reserved->filterPolicies; elem; elem = nextElem) { + nextElem = elem->next; + if (elem->filterPolicy && gIOUCFilterCallbacks->io_filter_release) { + gIOUCFilterCallbacks->io_filter_release(elem->filterPolicy); + } + IODelete(elem, IOUCFilterPolicy, 1); + } IODelete(reserved, ExpansionData, 1); } @@ -1813,6 +1977,17 @@ IOUserClient::clientMemoryForType( UInt32 type, return kIOReturnUnsupported; } +IOReturn +IOUserClient::clientMemoryForType( UInt32 type, + IOOptionBits * options, + OSSharedPtr& memory ) +{ + IOMemoryDescriptor* memoryRaw = nullptr; + IOReturn result = clientMemoryForType(type, options, &memoryRaw); + memory.reset(memoryRaw, OSNoRetain); + return result; +} + #if !__LP64__ IOMemoryMap * IOUserClient::mapClientMemory( @@ -1896,6 +2071,16 @@ IOUserClient::copyObjectForPortNameInTask(task_t task, mach_port_name_t port_nam return object ? kIOReturnSuccess : kIOReturnIPCError; } +IOReturn +IOUserClient::copyObjectForPortNameInTask(task_t task, mach_port_name_t port_name, + OSSharedPtr& obj) +{ + OSObject* objRaw = NULL; + IOReturn result = copyObjectForPortNameInTask(task, port_name, &objRaw); + obj.reset(objRaw, OSNoRetain); + return result; +} + IOReturn IOUserClient::adjustPortNameReferencesInTask(task_t task, mach_port_name_t port_name, mach_port_delta_t delta) { @@ -1939,6 +2124,16 @@ getTargetAndMethodForIndex(IOService **targetP, UInt32 index) return method; } +IOExternalMethod * +IOUserClient:: +getTargetAndMethodForIndex(OSSharedPtr& targetP, UInt32 index) +{ + IOService* targetPRaw = NULL; + IOExternalMethod* result = getTargetAndMethodForIndex(&targetPRaw, index); + targetP.reset(targetPRaw, OSRetain); + return result; +} + IOExternalAsyncMethod * IOUserClient:: getAsyncTargetAndMethodForIndex(IOService ** targetP, UInt32 index) @@ -1952,6 +2147,16 @@ getAsyncTargetAndMethodForIndex(IOService ** targetP, UInt32 index) return method; } +IOExternalAsyncMethod * +IOUserClient:: +getAsyncTargetAndMethodForIndex(OSSharedPtr& targetP, UInt32 index) +{ + IOService* targetPRaw = NULL; + IOExternalAsyncMethod* result = getAsyncTargetAndMethodForIndex(&targetPRaw, index); + targetP.reset(targetPRaw, OSRetain); + return result; +} + IOExternalTrap * IOUserClient:: getTargetAndTrapForIndex(IOService ** targetP, UInt32 index) @@ -2380,7 +2585,6 @@ is_io_iterator_is_valid( return kIOReturnSuccess; } - static kern_return_t internal_io_service_match_property_table( io_service_t _service, @@ -2395,9 +2599,12 @@ internal_io_service_match_property_table( OSDictionary * dict; assert(matching_size); + + obj = OSUnserializeXML(matching, matching_size); if ((dict = OSDynamicCast( OSDictionary, obj))) { + IOTaskRegistryCompatibilityMatching(current_task(), dict); *matches = service->passiveMatch( dict ); kr = kIOReturnSuccess; } else { @@ -2478,6 +2685,7 @@ internal_io_service_get_matching_services( obj = OSUnserializeXML(matching, matching_size); if ((dict = OSDynamicCast( OSDictionary, obj))) { + IOTaskRegistryCompatibilityMatching(current_task(), dict); *existing = IOUserIterator::withIterator(IOService::getMatchingServices( dict )); kr = kIOReturnSuccess; } else { @@ -2560,6 +2768,7 @@ internal_io_service_get_matching_service( obj = OSUnserializeXML(matching, matching_size); if ((dict = OSDynamicCast( OSDictionary, obj))) { + IOTaskRegistryCompatibilityMatching(current_task(), dict); *service = IOService::copyMatchingService( dict ); kr = *service ? kIOReturnSuccess : kIOReturnNotFound; } else { @@ -2637,9 +2846,10 @@ internal_io_service_add_notification( IOServiceUserNotification * userNotify = NULL; IONotifier * notify = NULL; const OSSymbol * sym; + OSObject * obj; OSDictionary * dict; IOReturn err; - unsigned long int userMsgType; + natural_t userMsgType; if (master_port != master_device_port) { return kIOReturnNotPrivileged; @@ -2657,11 +2867,13 @@ internal_io_service_add_notification( } assert(matching_size); - dict = OSDynamicCast(OSDictionary, OSUnserializeXML(matching, matching_size)); + obj = OSUnserializeXML(matching, matching_size); + dict = OSDynamicCast(OSDictionary, obj); if (!dict) { err = kIOReturnBadArgument; continue; } + IOTaskRegistryCompatibilityMatching(current_task(), dict); if ((sym == gIOPublishNotification) || (sym == gIOFirstPublishNotification)) { @@ -2707,8 +2919,8 @@ internal_io_service_add_notification( if (sym) { sym->release(); } - if (dict) { - dict->release(); + if (obj) { + obj->release(); } return err; @@ -3016,11 +3228,16 @@ is_io_connect_get_notification_semaphore( natural_t notification_type, semaphore_t *semaphore ) { + IOReturn ret; CHECK( IOUserClient, connection, client ); IOStatisticsClientCall(); - return client->getNotificationSemaphore((UInt32) notification_type, - semaphore ); + IORWLockWrite(client->lock); + ret = client->getNotificationSemaphore((UInt32) notification_type, + semaphore ); + IORWLockUnlock(client->lock); + + return ret; } /* Routine io_registry_get_root_entry */ @@ -3125,6 +3342,20 @@ is_io_registry_entry_from_path( entry = IORegistryEntry::fromPath( path ); + if (!entry && IOTaskRegistryCompatibility(current_task())) { + OSDictionary * matching; + const OSObject * objects[2] = { kOSBooleanTrue, NULL }; + const OSSymbol * keys[2] = { gIOCompatibilityMatchKey, gIOPathMatchKey }; + + objects[1] = OSString::withCStringNoCopy(path); + matching = OSDictionary::withObjects(objects, keys, 2, 2); + if (matching) { + entry = IOService::copyMatchingService(matching); + } + OSSafeReleaseNULL(matching); + OSSafeReleaseNULL(objects[1]); + } + *registry_entry = entry; return kIOReturnSuccess; @@ -3340,6 +3571,31 @@ is_io_registry_entry_get_registry_entry_id( return kIOReturnSuccess; } + +static OSObject * +IOCopyPropertyCompatible(IORegistryEntry * regEntry, const char * name) +{ + OSObject * obj; + OSObject * compatProps; + OSDictionary * props; + + obj = regEntry->copyProperty(name); + if (!obj + && IOTaskRegistryCompatibility(current_task()) + && (compatProps = regEntry->copyProperty(gIOCompatibilityPropertiesKey))) { + props = OSDynamicCast(OSDictionary, compatProps); + if (props) { + obj = props->getObject(name); + if (obj) { + obj->retain(); + } + } + compatProps->release(); + } + + return obj; +} + /* Routine io_registry_entry_get_property */ kern_return_t is_io_registry_entry_get_property_bytes( @@ -3366,7 +3622,7 @@ is_io_registry_entry_get_property_bytes( } #endif - obj = entry->copyProperty(property_name); + obj = IOCopyPropertyCompatible(entry, property_name); if (!obj) { return kIOReturnNoResources; } @@ -3423,7 +3679,7 @@ is_io_registry_entry_get_property( mach_msg_type_number_t *propertiesCnt ) { kern_return_t err; - vm_size_t len; + unsigned int len; OSObject * obj; CHECK( IORegistryEntry, registry_entry, entry ); @@ -3434,7 +3690,7 @@ is_io_registry_entry_get_property( } #endif - obj = entry->copyProperty(property_name); + obj = IOCopyPropertyCompatible(entry, property_name); if (!obj) { return kIOReturnNotFound; } @@ -3470,7 +3726,7 @@ is_io_registry_entry_get_property_recursively( mach_msg_type_number_t *propertiesCnt ) { kern_return_t err; - vm_size_t len; + unsigned int len; OSObject * obj; CHECK( IORegistryEntry, registry_entry, entry ); @@ -3559,8 +3815,9 @@ is_io_registry_entry_get_properties_bin_buf( io_buf_ptr_t *properties, mach_msg_type_number_t *propertiesCnt) { - kern_return_t err = kIOReturnSuccess; - vm_size_t len; + kern_return_t err = kIOReturnSuccess; + unsigned int len; + OSObject * compatProperties; OSSerialize * s; OSSerialize::Editor editor = NULL; void * editRef = NULL; @@ -3583,7 +3840,23 @@ is_io_registry_entry_get_properties_bin_buf( return kIOReturnNoMemory; } - if (!entry->serializeProperties(s)) { + if (IOTaskRegistryCompatibility(current_task()) + && (compatProperties = entry->copyProperty(gIOCompatibilityPropertiesKey))) { + OSDictionary * dict; + + dict = entry->dictionaryWithProperties(); + if (!dict) { + err = kIOReturnNoMemory; + } else { + dict->removeObject(gIOCompatibilityPropertiesKey); + dict->merge(OSDynamicCast(OSDictionary, compatProperties)); + if (!dict->serialize(s)) { + err = kIOReturnUnsupported; + } + dict->release(); + } + compatProperties->release(); + } else if (!entry->serializeProperties(s)) { err = kIOReturnUnsupported; } @@ -3635,7 +3908,7 @@ is_io_registry_entry_get_property_bin_buf( mach_msg_type_number_t *propertiesCnt ) { kern_return_t err; - vm_size_t len; + unsigned int len; OSObject * obj; const OSSymbol * sym; @@ -3656,10 +3929,24 @@ is_io_registry_entry_get_property_bin_buf( obj = entry->copyPropertyKeys(); } else { if ((kIORegistryIterateRecursively & options) && plane[0]) { - obj = entry->copyProperty(property_name, - IORegistryEntry::getPlane(plane), options ); + if (!IOTaskRegistryCompatibility(current_task())) { + obj = entry->copyProperty(property_name, + IORegistryEntry::getPlane(plane), options); + } else { + obj = IOCopyPropertyCompatible(entry, property_name); + if ((NULL == obj) && plane && (options & kIORegistryIterateRecursively)) { + IORegistryIterator * iter; + iter = IORegistryIterator::iterateOver(entry, IORegistryEntry::getPlane(plane), options); + if (iter) { + while ((NULL == obj) && (entry = iter->getNextObject())) { + obj = IOCopyPropertyCompatible(entry, property_name); + } + iter->release(); + } + } + } } else { - obj = entry->copyProperty(property_name); + obj = IOCopyPropertyCompatible(entry, property_name); } if (obj && gIORemoveOnReadProperties->containsObject(sym)) { entry->removeProperty(sym); @@ -3926,6 +4213,11 @@ is_io_service_open_extended( return kIOReturnBadArgument; } +#if CONFIG_MACF + if (mac_iokit_check_open_service(kauth_cred_get(), service, connect_type) != 0) { + return kIOReturnNotPermitted; + } +#endif do{ if (properties) { return kIOReturnUnsupported; @@ -3983,11 +4275,46 @@ is_io_service_open_extended( if (res == kIOReturnSuccess) { assert( OSDynamicCast(IOUserClient, client)); + if (!client->reserved) { + if (!client->reserve()) { + client->clientClose(); + OSSafeReleaseNULL(client); + res = kIOReturnNoMemory; + } + } + } + if (res == kIOReturnSuccess) { client->sharedInstance = (NULL != client->getProperty(kIOUserClientSharedInstanceKey)); - client->messageAppSuspended = (NULL != client->getProperty(kIOUserClientMessageAppSuspendedKey)); - client->closed = false; - client->lock = IOLockAlloc(); + if (client->sharedInstance) { + IOLockLock(gIOUserClientOwnersLock); + } + if (!client->lock) { + client->lock = IORWLockAlloc(); + client->filterLock = IOLockAlloc(); + + client->messageAppSuspended = (NULL != client->getProperty(kIOUserClientMessageAppSuspendedKey)); + { + OSObject * obj; + extern const OSSymbol * gIOSurfaceIdentifier; + obj = client->getProperty(kIOUserClientDefaultLockingKey); + if (obj) { + client->defaultLocking = (kOSBooleanFalse != client->getProperty(kIOUserClientDefaultLockingKey)); + } else { + const OSMetaClass * meta; + OSKext * kext; + meta = client->getMetaClass(); + kext = meta->getKext(); + if (!kext || !kext->hasDependency(gIOSurfaceIdentifier)) { + client->defaultLocking = true; + client->setProperty(kIOUserClientDefaultLockingKey, kOSBooleanTrue); + } + } + } + } + if (client->sharedInstance) { + IOLockUnlock(gIOUserClientOwnersLock); + } disallowAccess = (crossEndian && (kOSBooleanTrue != service->getProperty(kIOUserClientCrossEndianCompatibleKey)) @@ -4001,6 +4328,21 @@ is_io_service_open_extended( } #endif + if ((kIOReturnSuccess == res) + && gIOUCFilterCallbacks + && gIOUCFilterCallbacks->io_filter_resolver) { + io_filter_policy_t filterPolicy; + filterPolicy = client->filterForTask(owningTask, 0); + if (!filterPolicy) { + res = gIOUCFilterCallbacks->io_filter_resolver(owningTask, client, connect_type, &filterPolicy); + if (kIOReturnUnsupported == res) { + res = kIOReturnSuccess; + } else if (kIOReturnSuccess == res) { + client->filterForTask(owningTask, filterPolicy); + } + } + } + if (kIOReturnSuccess == res) { res = client->registerOwner(owningTask); } @@ -4042,9 +4384,9 @@ is_io_service_close( IOStatisticsClientCall(); if (client->sharedInstance || OSCompareAndSwap8(0, 1, &client->closed)) { - IOLockLock(client->lock); + IORWLockWrite(client->lock); client->clientClose(); - IOLockUnlock(client->lock); + IORWLockUnlock(client->lock); } else { IOLog("ignored is_io_service_close(0x%qx,%s)\n", client->getRegistryEntryID(), client->getName()); @@ -4085,10 +4427,10 @@ is_io_connect_set_notification_port( CHECK( IOUserClient, connection, client ); IOStatisticsClientCall(); - IOLockLock(client->lock); + IORWLockWrite(client->lock); ret = client->registerNotificationPort( port, notification_type, (io_user_reference_t) reference ); - IOLockUnlock(client->lock); + IORWLockUnlock(client->lock); return ret; } @@ -4104,10 +4446,10 @@ is_io_connect_set_notification_port_64( CHECK( IOUserClient, connection, client ); IOStatisticsClientCall(); - IOLockLock(client->lock); + IORWLockWrite(client->lock); ret = client->registerNotificationPort( port, notification_type, reference ); - IOLockUnlock(client->lock); + IORWLockUnlock(client->lock); return ret; } @@ -4133,7 +4475,13 @@ is_io_connect_map_memory_into_task } IOStatisticsClientCall(); + if (client->defaultLocking) { + IORWLockWrite(client->lock); + } map = client->mapClientMemory64( memory_type, into_task, flags, *address ); + if (client->defaultLocking) { + IORWLockUnlock(client->lock); + } if (map) { *address = map->getAddress(); @@ -4242,7 +4590,13 @@ is_io_connect_unmap_memory_from_task } IOStatisticsClientCall(); + if (client->defaultLocking) { + IORWLockWrite(client->lock); + } err = client->clientMemoryForType((UInt32) memory_type, &options, &memory ); + if (client->defaultLocking) { + IORWLockUnlock(client->lock); + } if (memory && (kIOReturnSuccess == err)) { options = (options & ~kIOMapUserOptionsMask) @@ -4258,7 +4612,8 @@ is_io_connect_unmap_memory_from_task IOLockUnlock( gIOObjectPortLock); mach_port_name_t name = 0; - if (from_task != current_task()) { + bool is_shared_instance_or_from_current_task = from_task != current_task() || client->sharedInstance; + if (is_shared_instance_or_from_current_task) { name = IOMachPort::makeSendRightForTask( from_task, map, IKOT_IOKIT_OBJECT ); map->release(); } @@ -4270,7 +4625,7 @@ is_io_connect_unmap_memory_from_task } else { IOMachPort::releasePortForObject( map, IKOT_IOKIT_OBJECT ); } - if (from_task == current_task()) { + if (!is_shared_instance_or_from_current_task) { map->release(); } } else { @@ -4308,8 +4663,17 @@ is_io_connect_add_client( CHECK( IOUserClient, connection, client ); CHECK( IOUserClient, connect_to, to ); + IOReturn ret; + IOStatisticsClientCall(); - return client->connectClient( to ); + if (client->defaultLocking) { + IORWLockWrite(client->lock); + } + ret = client->connectClient( to ); + if (client->defaultLocking) { + IORWLockUnlock(client->lock); + } + return ret; } @@ -4388,7 +4752,21 @@ is_io_connect_method_var_output args.structureOutputDescriptorSize = 0; IOStatisticsClientCall(); - ret = client->externalMethod( selector, &args ); + ret = kIOReturnSuccess; + + io_filter_policy_t filterPolicy = client->filterForTask(current_task(), 0); + if (filterPolicy && gIOUCFilterCallbacks->io_filter_applier) { + ret = gIOUCFilterCallbacks->io_filter_applier(filterPolicy, io_filter_type_external_method, selector); + } + if (kIOReturnSuccess == ret) { + if (client->defaultLocking) { + IORWLockRead(client->lock); + } + ret = client->externalMethod( selector, &args ); + if (client->defaultLocking) { + IORWLockUnlock(client->lock); + } + } *scalar_outputCnt = args.scalarOutputCount; *inband_outputCnt = args.structureOutputSize; @@ -4396,7 +4774,7 @@ is_io_connect_method_var_output if (var_outputCnt && var_output && (kIOReturnSuccess == ret)) { OSSerialize * serialize; OSData * data; - vm_size_t len; + unsigned int len; if ((serialize = OSDynamicCast(OSSerialize, structureVariableOutputData))) { len = serialize->getLength(); @@ -4467,8 +4845,13 @@ is_io_connect_method if (ool_input && (ool_input_size <= sizeof(io_struct_inband_t))) { return kIOReturnIPCError; } - if (ool_output && (*ool_output_size <= sizeof(io_struct_inband_t))) { - return kIOReturnIPCError; + if (ool_output) { + if (*ool_output_size <= sizeof(io_struct_inband_t)) { + return kIOReturnIPCError; + } + if (*ool_output_size > UINT_MAX) { + return kIOReturnIPCError; + } } if (ool_input) { @@ -4491,10 +4874,25 @@ is_io_connect_method } args.structureOutputDescriptor = outputMD; - args.structureOutputDescriptorSize = ool_output_size ? *ool_output_size : 0; + args.structureOutputDescriptorSize = ool_output_size + ? ((typeof(args.structureOutputDescriptorSize)) * ool_output_size) + : 0; IOStatisticsClientCall(); - ret = client->externalMethod( selector, &args ); + ret = kIOReturnSuccess; + io_filter_policy_t filterPolicy = client->filterForTask(current_task(), 0); + if (filterPolicy && gIOUCFilterCallbacks->io_filter_applier) { + ret = gIOUCFilterCallbacks->io_filter_applier(filterPolicy, io_filter_type_external_method, selector); + } + if (kIOReturnSuccess == ret) { + if (client->defaultLocking) { + IORWLockRead(client->lock); + } + ret = client->externalMethod( selector, &args ); + if (client->defaultLocking) { + IORWLockUnlock(client->lock); + } + } *scalar_outputCnt = args.scalarOutputCount; *inband_outputCnt = args.structureOutputSize; @@ -4540,6 +4938,10 @@ is_io_connect_async_method IOMemoryDescriptor * inputMD = NULL; IOMemoryDescriptor * outputMD = NULL; + if (referenceCnt < 1) { + return kIOReturnBadArgument; + } + bzero(&args.__reserved[0], sizeof(args.__reserved)); args.__reservedA = 0; args.version = kIOExternalMethodArgumentsCurrentVersion; @@ -4565,8 +4967,13 @@ is_io_connect_async_method if (ool_input && (ool_input_size <= sizeof(io_struct_inband_t))) { return kIOReturnIPCError; } - if (ool_output && (*ool_output_size <= sizeof(io_struct_inband_t))) { - return kIOReturnIPCError; + if (ool_output) { + if (*ool_output_size <= sizeof(io_struct_inband_t)) { + return kIOReturnIPCError; + } + if (*ool_output_size > UINT_MAX) { + return kIOReturnIPCError; + } } if (ool_input) { @@ -4589,10 +4996,23 @@ is_io_connect_async_method } args.structureOutputDescriptor = outputMD; - args.structureOutputDescriptorSize = *ool_output_size; + args.structureOutputDescriptorSize = ((typeof(args.structureOutputDescriptorSize)) * ool_output_size); IOStatisticsClientCall(); - ret = client->externalMethod( selector, &args ); + ret = kIOReturnSuccess; + io_filter_policy_t filterPolicy = client->filterForTask(current_task(), 0); + if (filterPolicy && gIOUCFilterCallbacks->io_filter_applier) { + ret = gIOUCFilterCallbacks->io_filter_applier(filterPolicy, io_filter_type_external_async_method, selector); + } + if (kIOReturnSuccess == ret) { + if (client->defaultLocking) { + IORWLockRead(client->lock); + } + ret = client->externalMethod( selector, &args ); + if (client->defaultLocking) { + IORWLockUnlock(client->lock); + } + } *scalar_outputCnt = args.scalarOutputCount; *inband_outputCnt = args.structureOutputSize; @@ -5463,10 +5883,6 @@ shim_io_async_method_structureI_structureO( return err; } -#if !NO_KEXTD -bool gIOKextdClearedBusy = false; -#endif - /* Routine io_catalog_send_data */ kern_return_t is_io_catalog_send_data( @@ -5496,7 +5912,7 @@ is_io_catalog_send_data( return kIOReturnBadArgument; } - if (!IOTaskHasEntitlement(current_task(), kOSKextManagementEntitlement)) { + if (!IOTaskHasEntitlement(current_task(), kIOCatalogManagementEntitlement)) { OSString * taskName = IOCopyLogNameForPID(proc_selfpid()); IOLog("IOCatalogueSendData(%s): Not entitled\n", taskName ? taskName->getCStringNoCopy() : ""); OSSafeReleaseNULL(taskName); @@ -5582,33 +5998,11 @@ is_io_catalog_send_data( case kIOCatalogStartMatching__Removed: case kIOCatalogRemoveKernelLinker__Removed: - kr = KERN_NOT_SUPPORTED; - break; - case kIOCatalogKextdActive: -#if !NO_KEXTD - IOServiceTrace(IOSERVICE_KEXTD_ALIVE, 0, 0, 0, 0); - OSKext::setKextdActive(); - - /* Dump all nonloaded startup extensions; kextd will now send them - * down on request. - */ - OSKext::flushNonloadedKexts( /* flushPrelinkedKexts */ false); -#endif - kr = kIOReturnSuccess; + case kIOCatalogKextdFinishedLaunching: + kr = KERN_NOT_SUPPORTED; break; - case kIOCatalogKextdFinishedLaunching: { -#if !NO_KEXTD - if (!gIOKextdClearedBusy) { - IOService::kextdLaunched(); - gIOKextdClearedBusy = true; - } -#endif - kr = kIOReturnSuccess; - } - break; - default: kr = kIOReturnBadArgument; break; @@ -5645,28 +6039,7 @@ is_io_catalog_terminate( switch (flag) { #if !defined(SECURE_KERNEL) case kIOCatalogServiceTerminate: - OSIterator * iter; - IOService * service; - - iter = IORegistryIterator::iterateOver(gIOServicePlane, - kIORegistryIterateRecursively); - if (!iter) { - return kIOReturnNoMemory; - } - - do { - iter->reset(); - while ((service = (IOService *)iter->getNextObject())) { - if (service->metaCast(name)) { - if (!service->terminate( kIOServiceRequired - | kIOServiceSynchronous)) { - kr = kIOReturnUnsupported; - break; - } - } - } - } while (!service && !iter->isValid()); - iter->release(); + kr = gIOCatalogue->terminateDrivers(NULL, name); break; case kIOCatalogModuleUnload: @@ -5711,14 +6084,14 @@ is_io_catalog_get_data( if (kr == kIOReturnSuccess) { vm_offset_t data; vm_map_copy_t copy; - vm_size_t size; + unsigned int size; size = s->getLength(); kr = vm_allocate_kernel(kernel_map, &data, size, VM_FLAGS_ANYWHERE, VM_KERN_MEMORY_IOKIT); if (kr == kIOReturnSuccess) { bcopy(s->text(), (void *)data, size); kr = vm_map_copyin(kernel_map, (vm_map_address_t)data, - (vm_map_size_t)size, true, ©); + size, true, ©); *outData = (char *)copy; *outDataCount = size; } @@ -5810,11 +6183,17 @@ iokit_user_client_trap(struct iokit_user_client_trap_args *args) } OSSafeReleaseNULL(object); } else if ((userClient = OSDynamicCast(IOUserClient, iokit_lookup_connect_ref_current_task((mach_port_name_t) ref)))) { - IOExternalTrap *trap; + IOExternalTrap *trap = NULL; IOService *target = NULL; - trap = userClient->getTargetAndTrapForIndex(&target, args->index); - + result = kIOReturnSuccess; + io_filter_policy_t filterPolicy = userClient->filterForTask(current_task(), 0); + if (filterPolicy && gIOUCFilterCallbacks->io_filter_applier) { + result = gIOUCFilterCallbacks->io_filter_applier(filterPolicy, io_filter_type_trap, args->index); + } + if (kIOReturnSuccess == result) { + trap = userClient->getTargetAndTrapForIndex(&target, args->index); + } if (trap && target) { IOTrap func; @@ -5995,11 +6374,28 @@ IOUserClient::externalMethod( uint32_t selector, IOExternalMethodArguments * arg } } - args->structureOutputSize = structureOutputSize; + if (structureOutputSize > UINT_MAX) { + structureOutputSize = 0; + err = kIOReturnBadArgument; + } + + args->structureOutputSize = ((typeof(args->structureOutputSize))structureOutputSize); return err; } +IOReturn +IOUserClient::registerFilterCallbacks(const struct io_filter_callbacks *callbacks, size_t size) +{ + if (size < sizeof(*callbacks)) { + return kIOReturnBadArgument; + } + if (!OSCompareAndSwapPtr(NULL, __DECONST(void *, callbacks), &gIOUCFilterCallbacks)) { + return kIOReturnBusy; + } + return kIOReturnSuccess; +} + #if __LP64__ OSMetaClassDefineReservedUnused(IOUserClient, 0); OSMetaClassDefineReservedUnused(IOUserClient, 1);