X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/4bd07ac2140668789aa3ee8ec4dde4a3e0a3bba5..e8c3f78193f1895ea514044358b93b1add9322f3:/iokit/Kernel/IOUserClient.cpp?ds=inline diff --git a/iokit/Kernel/IOUserClient.cpp b/iokit/Kernel/IOUserClient.cpp index 8c628ddf1..b99f027dd 100644 --- a/iokit/Kernel/IOUserClient.cpp +++ b/iokit/Kernel/IOUserClient.cpp @@ -37,14 +37,18 @@ #include #include #include +#include #include #include +#include #include #include #include #include #include +#include + #if CONFIG_MACF extern "C" { @@ -69,8 +73,9 @@ extern "C" { enum { - kIOUCAsync0Flags = 3ULL, - kIOUCAsync64Flag = 1ULL + kIOUCAsync0Flags = 3ULL, + kIOUCAsync64Flag = 1ULL, + kIOUCAsyncErrorLoggedFlag = 2ULL }; #if IOKITSTATS @@ -99,47 +104,34 @@ do { \ #endif /* IOKITSTATS */ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -// definitions we should get from osfmk - -//typedef struct ipc_port * ipc_port_t; -typedef natural_t ipc_kobject_type_t; - -#define IKOT_IOKIT_SPARE 27 -#define IKOT_IOKIT_CONNECT 29 -#define IKOT_IOKIT_OBJECT 30 - -extern "C" { - -extern ipc_port_t iokit_alloc_object_port( io_object_t obj, - ipc_kobject_type_t type ); - -extern kern_return_t iokit_destroy_object_port( ipc_port_t port ); +#if DEVELOPMENT || DEBUG -extern mach_port_name_t iokit_make_send_right( task_t task, - io_object_t obj, ipc_kobject_type_t type ); +#define FAKE_STACK_FRAME(a) \ + const void ** __frameptr; \ + const void * __retaddr; \ + __frameptr = (typeof(__frameptr)) __builtin_frame_address(0); \ + __retaddr = __frameptr[1]; \ + __frameptr[1] = (a); -extern kern_return_t iokit_mod_send_right( task_t task, mach_port_name_t name, mach_port_delta_t delta ); +#define FAKE_STACK_FRAME_END() \ + __frameptr[1] = __retaddr; -extern io_object_t iokit_lookup_connect_ref(io_object_t clientRef, ipc_space_t task); +#else /* DEVELOPMENT || DEBUG */ -extern io_object_t iokit_lookup_connect_ref_current_task(io_object_t clientRef); +#define FAKE_STACK_FRAME(a) +#define FAKE_STACK_FRAME_END() -extern ipc_port_t master_device_port; +#endif /* DEVELOPMENT || DEBUG */ -extern void iokit_retain_port( ipc_port_t port ); -extern void iokit_release_port( ipc_port_t port ); -extern void iokit_release_port_send( ipc_port_t port ); +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -extern kern_return_t iokit_switch_object_port( ipc_port_t port, io_object_t obj, ipc_kobject_type_t type ); +extern "C" { #include #include } /* extern "C" */ - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // IOMachPort maps OSObjects to ports, avoiding adding an ivar to OSObject. @@ -179,17 +171,28 @@ static IOLock * gIOObjectPortLock; // not in dictForType() for debugging ease static OSDictionary * gIOObjectPorts; static OSDictionary * gIOConnectPorts; +static OSDictionary * gIOIdentifierPorts; OSDictionary * IOMachPort::dictForType( ipc_kobject_type_t type ) { OSDictionary ** dict; - if( IKOT_IOKIT_OBJECT == type ) - dict = &gIOObjectPorts; - else if( IKOT_IOKIT_CONNECT == type ) - dict = &gIOConnectPorts; - else - return( 0 ); + switch (type) + { + case IKOT_IOKIT_OBJECT: + dict = &gIOObjectPorts; + break; + case IKOT_IOKIT_CONNECT: + dict = &gIOConnectPorts; + break; + case IKOT_IOKIT_IDENT: + dict = &gIOIdentifierPorts; + break; + default: + panic("dictForType %d", type); + dict = NULL; + break; + } if( 0 == *dict) *dict = OSDictionary::withCapacity( 1 ); @@ -247,6 +250,7 @@ bool IOMachPort::noMoreSendersForObject( OSObject * obj, { OSDictionary * dict; IOMachPort * machPort; + IOUserClient * uc; bool destroyed = true; IOTakeLock( gIOObjectPortLock); @@ -257,10 +261,15 @@ bool IOMachPort::noMoreSendersForObject( OSObject * obj, machPort = (IOMachPort *) dict->getObject( (const OSSymbol *) obj ); if( machPort) { destroyed = (machPort->mscount <= *mscount); - if( destroyed) + if (!destroyed) *mscount = machPort->mscount; + else + { + if ((IKOT_IOKIT_CONNECT == type) && (uc = OSDynamicCast(IOUserClient, obj))) + { + uc->noMoreSenders(); + } dict->removeObject( (const OSSymbol *) obj ); - else - *mscount = machPort->mscount; + } } obj->release(); } @@ -276,6 +285,8 @@ void IOMachPort::releasePortForObject( OSObject * obj, OSDictionary * dict; IOMachPort * machPort; + assert(IKOT_IOKIT_CONNECT != type); + IOTakeLock( gIOObjectPortLock); if( (dict = dictForType( type ))) { @@ -324,14 +335,18 @@ void IOUserClient::destroyUserReferences( OSObject * obj ) if (port) { IOUserClient * uc; - if ((uc = OSDynamicCast(IOUserClient, obj)) && uc->mappings) + if ((uc = OSDynamicCast(IOUserClient, obj))) { - dict->setObject((const OSSymbol *) uc->mappings, port); - iokit_switch_object_port(port->port, uc->mappings, IKOT_IOKIT_CONNECT); - - uc->mappings->release(); - uc->mappings = 0; - } + uc->noMoreSenders(); + if (uc->mappings) + { + dict->setObject((const OSSymbol *) uc->mappings, port); + iokit_switch_object_port(port->port, uc->mappings, IKOT_IOKIT_CONNECT); + + uc->mappings->release(); + uc->mappings = 0; + } + } dict->removeObject( (const OSSymbol *) obj ); } } @@ -368,6 +383,7 @@ public: virtual void reset() APPLE_KEXT_OVERRIDE; virtual bool isValid() APPLE_KEXT_OVERRIDE; virtual OSObject * getNextObject() APPLE_KEXT_OVERRIDE; + virtual OSObject * copyNextObject(); }; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ @@ -456,11 +472,20 @@ IOUserIterator::isValid() OSObject * IOUserIterator::getNextObject() { - OSObject * ret; + assert(false); + return (NULL); +} + +OSObject * +IOUserIterator::copyNextObject() +{ + OSObject * ret = NULL; IOLockLock(lock); - assert(OSDynamicCast(OSIterator, userIteratorObject)); - ret = ((OSIterator *)userIteratorObject)->getNextObject(); + if (userIteratorObject) { + ret = ((OSIterator *)userIteratorObject)->getNextObject(); + if (ret) ret->retain(); + } IOLockUnlock(lock); return (ret); @@ -472,10 +497,19 @@ extern "C" { // functions called from osfmk/device/iokit_rpc.c void -iokit_add_reference( io_object_t obj ) +iokit_add_reference( io_object_t obj, ipc_kobject_type_t type ) { - if( obj) - obj->retain(); + IOUserClient * uc; + + if (!obj) return; + + if ((IKOT_IOKIT_CONNECT == type) + && (uc = OSDynamicCast(IOUserClient, obj))) + { + OSIncrementAtomic(&uc->__ipc); + } + + obj->retain(); } void @@ -485,6 +519,43 @@ iokit_remove_reference( io_object_t obj ) obj->release(); } +void +iokit_remove_connect_reference( io_object_t obj ) +{ + IOUserClient * uc; + bool finalize = false; + + if (!obj) return; + + if ((uc = OSDynamicCast(IOUserClient, obj))) + { + if (1 == OSDecrementAtomic(&uc->__ipc) && uc->isInactive()) + { + IOLockLock(gIOObjectPortLock); + if ((finalize = uc->__ipcFinal)) uc->__ipcFinal = false; + IOLockUnlock(gIOObjectPortLock); + } + if (finalize) uc->scheduleFinalize(true); + } + + obj->release(); +} + +bool +IOUserClient::finalizeUserReferences(OSObject * obj) +{ + IOUserClient * uc; + bool ok = true; + + if ((uc = OSDynamicCast(IOUserClient, obj))) + { + IOLockLock(gIOObjectPortLock); + if ((uc->__ipcFinal = (0 != uc->__ipc))) ok = false; + IOLockUnlock(gIOObjectPortLock); + } + return (ok); +} + ipc_port_t iokit_port_for_object( io_object_t obj, ipc_kobject_type_t type ) { @@ -518,10 +589,13 @@ iokit_client_died( io_object_t obj, ipc_port_t /* port */, if( IKOT_IOKIT_CONNECT == type) { - if( (client = OSDynamicCast( IOUserClient, obj ))) { - IOStatisticsClientCall(); + if( (client = OSDynamicCast( IOUserClient, obj ))) + { + IOStatisticsClientCall(); + IOLockLock(client->lock); client->clientDied(); - } + IOLockUnlock(client->lock); + } } else if( IKOT_IOKIT_OBJECT == type) { @@ -552,8 +626,8 @@ class IOServiceUserNotification : public IOUserNotification PingMsg * pingMsg; vm_size_t msgSize; OSArray * newSet; - OSObject * lastEntry; bool armed; + bool ipcLogged; public: @@ -561,12 +635,14 @@ public: void * reference, vm_size_t referenceSize, bool clientIs64 ); virtual void free() APPLE_KEXT_OVERRIDE; + void invalidatePort(void); static bool _handler( void * target, void * ref, IOService * newService, IONotifier * notifier ); virtual bool handler( void * ref, IOService * newService ); virtual OSObject * getNextObject() APPLE_KEXT_OVERRIDE; + virtual OSObject * copyNextObject() APPLE_KEXT_OVERRIDE; }; class IOServiceMessageUserNotification : public IOUserNotification @@ -584,6 +660,7 @@ class IOServiceMessageUserNotification : public IOUserNotification vm_size_t msgSize; uint8_t clientIs64; int owningPID; + bool ipcLogged; public: @@ -593,6 +670,7 @@ public: bool clientIs64 ); virtual void free() APPLE_KEXT_OVERRIDE; + void invalidatePort(void); static IOReturn _handler( void * target, void * ref, UInt32 messageType, IOService * provider, @@ -602,6 +680,7 @@ public: void * messageArgument, vm_size_t argSize ); virtual OSObject * getNextObject() APPLE_KEXT_OVERRIDE; + virtual OSObject * copyNextObject() APPLE_KEXT_OVERRIDE; }; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ @@ -698,16 +777,19 @@ bool IOServiceUserNotification::init( mach_port_t port, natural_t type, return( true ); } +void IOServiceUserNotification::invalidatePort(void) +{ + if (pingMsg) pingMsg->msgHdr.msgh_remote_port = MACH_PORT_NULL; +} + void IOServiceUserNotification::free( void ) { PingMsg * _pingMsg; vm_size_t _msgSize; OSArray * _newSet; - OSObject * _lastEntry; _pingMsg = pingMsg; _msgSize = msgSize; - _lastEntry = lastEntry; _newSet = newSet; super::free(); @@ -719,9 +801,6 @@ void IOServiceUserNotification::free( void ) IOFree(_pingMsg, _msgSize); } - if( _lastEntry) - _lastEntry->release(); - if( _newSet) _newSet->release(); } @@ -768,22 +847,27 @@ bool IOServiceUserNotification::handler( void * ref, if( port) iokit_release_port( port ); - if( KERN_SUCCESS != kr) - IOLog("%s: mach_msg_send_from_kernel_proper {%x}\n", __FILE__, kr ); + if( (KERN_SUCCESS != kr) && !ipcLogged) + { + ipcLogged = true; + IOLog("%s: mach_msg_send_from_kernel_proper(0x%x)\n", __PRETTY_FUNCTION__, kr ); + } } return( true ); } - OSObject * IOServiceUserNotification::getNextObject() +{ + assert(false); + return (NULL); +} + +OSObject * IOServiceUserNotification::copyNextObject() { unsigned int count; OSObject * result; - IOTakeLock( lock ); - - if( lastEntry) - lastEntry->release(); + IOLockLock(lock); count = newSet->getCount(); if( count ) { @@ -794,9 +878,8 @@ OSObject * IOServiceUserNotification::getNextObject() result = 0; armed = true; } - lastEntry = result; - IOUnlock( lock ); + IOLockUnlock(lock); return( result ); } @@ -822,7 +905,7 @@ bool IOServiceMessageUserNotification::init( mach_port_t port, natural_t type, owningPID = proc_selfpid(); extraSize += sizeof(IOServiceInterestContent64); - msgSize = sizeof(PingMsg) - sizeof(OSAsyncReference64) + referenceSize + extraSize; + msgSize = sizeof(PingMsg) - sizeof(OSAsyncReference64) + referenceSize; pingMsg = (PingMsg *) IOMalloc( msgSize); if( !pingMsg) return( false ); @@ -850,6 +933,11 @@ bool IOServiceMessageUserNotification::init( mach_port_t port, natural_t type, return( true ); } +void IOServiceMessageUserNotification::invalidatePort(void) +{ + if (pingMsg) pingMsg->msgHdr.msgh_remote_port = MACH_PORT_NULL; +} + void IOServiceMessageUserNotification::free( void ) { PingMsg * _pingMsg; @@ -878,13 +966,17 @@ IOReturn IOServiceMessageUserNotification::_handler( void * target, void * ref, IOReturn IOServiceMessageUserNotification::handler( void * ref, UInt32 messageType, IOService * provider, - void * messageArgument, vm_size_t argSize ) + void * messageArgument, vm_size_t callerArgSize ) { + enum { kLocalMsgSize = 0x100 }; + uint64_t stackMsg[kLocalMsgSize / sizeof(uint64_t)]; + void * allocMsg; kern_return_t kr; + vm_size_t argSize; + vm_size_t thisMsgSize; ipc_port_t thisPort, providerPort; - IOServiceInterestContent64 * data = (IOServiceInterestContent64 *) - ((((uint8_t *) pingMsg) + msgSize) - pingMsg->notifyHeader.size); - // == pingMsg->notifyHeader.content; + struct PingMsg * thisMsg; + IOServiceInterestContent64 * data; if (kIOMessageCopyClientID == messageType) { @@ -892,24 +984,16 @@ IOReturn IOServiceMessageUserNotification::handler( void * ref, return (kIOReturnSuccess); } - data->messageType = messageType; - - if( argSize == 0) + if (callerArgSize == 0) { - data->messageArgument[0] = (io_user_reference_t) messageArgument; - if (clientIs64) - argSize = sizeof(data->messageArgument[0]); - else - { - data->messageArgument[0] |= (data->messageArgument[0] << 32); - argSize = sizeof(uint32_t); - } + if (clientIs64) argSize = sizeof(data->messageArgument[0]); + else argSize = sizeof(uint32_t); } else { - if( argSize > kIOUserNotifyMaxMessageSize) - argSize = kIOUserNotifyMaxMessageSize; - bcopy( messageArgument, data->messageArgument, argSize ); + if( callerArgSize > kIOUserNotifyMaxMessageSize) + callerArgSize = kIOUserNotifyMaxMessageSize; + argSize = callerArgSize; } // adjust message size for ipc restrictions @@ -917,20 +1001,55 @@ IOReturn IOServiceMessageUserNotification::handler( void * ref, type = pingMsg->notifyHeader.type; type &= ~(kIOKitNoticationMsgSizeMask << kIOKitNoticationTypeSizeAdjShift); type |= ((argSize & kIOKitNoticationMsgSizeMask) << kIOKitNoticationTypeSizeAdjShift); - pingMsg->notifyHeader.type = type; argSize = (argSize + kIOKitNoticationMsgSizeMask) & ~kIOKitNoticationMsgSizeMask; - pingMsg->msgHdr.msgh_size = msgSize - pingMsg->notifyHeader.size - + sizeof( IOServiceInterestContent64 ) - - sizeof( data->messageArgument) - + argSize; + thisMsgSize = msgSize + + sizeof( IOServiceInterestContent64 ) + - sizeof( data->messageArgument) + + argSize; + + if (thisMsgSize > sizeof(stackMsg)) + { + allocMsg = IOMalloc(thisMsgSize); + if (!allocMsg) return (kIOReturnNoMemory); + thisMsg = (typeof(thisMsg)) allocMsg; + } + else + { + allocMsg = 0; + thisMsg = (typeof(thisMsg)) stackMsg; + } + + bcopy(pingMsg, thisMsg, msgSize); + thisMsg->notifyHeader.type = type; + data = (IOServiceInterestContent64 *) (((uint8_t *) thisMsg) + msgSize); + // == pingMsg->notifyHeader.content; + data->messageType = messageType; + + if (callerArgSize == 0) + { + data->messageArgument[0] = (io_user_reference_t) messageArgument; + if (!clientIs64) + { + data->messageArgument[0] |= (data->messageArgument[0] << 32); + } + } + else + { + bcopy( messageArgument, data->messageArgument, callerArgSize ); + bzero((void *)(((uintptr_t) &data->messageArgument[0]) + callerArgSize), argSize - callerArgSize); + } + + thisMsg->notifyHeader.type = type; + thisMsg->msgHdr.msgh_size = thisMsgSize; providerPort = iokit_port_for_object( provider, IKOT_IOKIT_OBJECT ); - pingMsg->ports[0].name = providerPort; + thisMsg->ports[0].name = providerPort; thisPort = iokit_port_for_object( this, IKOT_IOKIT_OBJECT ); - pingMsg->msgHdr.msgh_local_port = thisPort; - kr = mach_msg_send_from_kernel_with_options( &pingMsg->msgHdr, - pingMsg->msgHdr.msgh_size, + thisMsg->msgHdr.msgh_local_port = thisPort; + + kr = mach_msg_send_from_kernel_with_options( &thisMsg->msgHdr, + thisMsg->msgHdr.msgh_size, (MACH_SEND_MSG | MACH_SEND_ALWAYS | MACH_SEND_IMPORTANCE), 0); if( thisPort) @@ -938,8 +1057,14 @@ IOReturn IOServiceMessageUserNotification::handler( void * ref, if( providerPort) iokit_release_port( providerPort ); - if( KERN_SUCCESS != kr) - IOLog("%s: mach_msg_send_from_kernel_proper {%x}\n", __FILE__, kr ); + if (allocMsg) + IOFree(allocMsg, thisMsgSize); + + if((KERN_SUCCESS != kr) && !ipcLogged) + { + ipcLogged = true; + IOLog("%s: mach_msg_send_from_kernel_proper (0x%x)\n", __PRETTY_FUNCTION__, kr ); + } return( kIOReturnSuccess ); } @@ -949,17 +1074,24 @@ OSObject * IOServiceMessageUserNotification::getNextObject() return( 0 ); } +OSObject * IOServiceMessageUserNotification::copyNextObject() +{ + return( NULL ); +} + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #undef super #define super IOService OSDefineMetaClassAndAbstractStructors( IOUserClient, IOService ) +IOLock * gIOUserClientOwnersLock; + void IOUserClient::initialize( void ) { - gIOObjectPortLock = IOLockAlloc(); - - assert( gIOObjectPortLock ); + gIOObjectPortLock = IOLockAlloc(); + gIOUserClientOwnersLock = IOLockAlloc(); + assert(gIOObjectPortLock && gIOUserClientOwnersLock); } void IOUserClient::setAsyncReference(OSAsyncReference asyncRef, @@ -1284,22 +1416,146 @@ bool IOUserClient::reserve() return true; } +struct IOUserClientOwner +{ + task_t task; + queue_chain_t taskLink; + IOUserClient * uc; + queue_chain_t ucLink; +}; + +IOReturn +IOUserClient::registerOwner(task_t task) +{ + IOUserClientOwner * owner; + IOReturn ret; + bool newOwner; + + IOLockLock(gIOUserClientOwnersLock); + + newOwner = true; + ret = kIOReturnSuccess; + + if (!owners.next) queue_init(&owners); + else + { + queue_iterate(&owners, owner, IOUserClientOwner *, ucLink) + { + if (task != owner->task) continue; + newOwner = false; + break; + } + } + if (newOwner) + { + owner = IONew(IOUserClientOwner, 1); + if (!owner) ret = kIOReturnNoMemory; + else + { + owner->task = task; + owner->uc = this; + queue_enter_first(&owners, owner, IOUserClientOwner *, ucLink); + queue_enter_first(task_io_user_clients(task), owner, IOUserClientOwner *, taskLink); + } + } + + IOLockUnlock(gIOUserClientOwnersLock); + + return (ret); +} + +void +IOUserClient::noMoreSenders(void) +{ + IOUserClientOwner * owner; + + IOLockLock(gIOUserClientOwnersLock); + + if (owners.next) + { + while (!queue_empty(&owners)) + { + owner = (IOUserClientOwner *)(void *) queue_first(&owners); + queue_remove(task_io_user_clients(owner->task), owner, IOUserClientOwner *, taskLink); + queue_remove(&owners, owner, IOUserClientOwner *, ucLink); + IODelete(owner, IOUserClientOwner, 1); + } + owners.next = owners.prev = NULL; + } + + IOLockUnlock(gIOUserClientOwnersLock); +} + +extern "C" kern_return_t +iokit_task_terminate(task_t task) +{ + IOUserClientOwner * owner; + IOUserClient * dead; + IOUserClient * uc; + queue_head_t * taskque; + + IOLockLock(gIOUserClientOwnersLock); + + taskque = task_io_user_clients(task); + dead = NULL; + while (!queue_empty(taskque)) + { + owner = (IOUserClientOwner *)(void *) queue_first(taskque); + uc = owner->uc; + queue_remove(taskque, owner, IOUserClientOwner *, taskLink); + queue_remove(&uc->owners, owner, IOUserClientOwner *, ucLink); + if (queue_empty(&uc->owners)) + { + uc->retain(); + IOLog("destroying out of band connect for %s\n", uc->getName()); + // now using the uc queue head as a singly linked queue, + // leaving .next as NULL to mark it empty + uc->owners.next = NULL; + uc->owners.prev = (queue_entry_t) dead; + dead = uc; + } + IODelete(owner, IOUserClientOwner, 1); + } + + IOLockUnlock(gIOUserClientOwnersLock); + + while (dead) + { + uc = dead; + dead = (IOUserClient *)(void *) dead->owners.prev; + uc->owners.prev = NULL; + if (uc->sharedInstance || !uc->closed) uc->clientDied(); + uc->release(); + } + + return (KERN_SUCCESS); +} + void IOUserClient::free() { - if( mappings) - mappings->release(); + if( mappings) mappings->release(); + if (lock) IOLockFree(lock); IOStatisticsUnregisterCounter(); - if (reserved) - IODelete(reserved, ExpansionData, 1); + assert(!owners.next); + assert(!owners.prev); + + if (reserved) IODelete(reserved, ExpansionData, 1); super::free(); } IOReturn IOUserClient::clientDied( void ) { - return( clientClose()); + IOReturn ret = kIOReturnNotReady; + + if (sharedInstance || OSCompareAndSwap8(0, 1, &closed)) + { + ret = clientClose(); + } + + return (ret); } IOReturn IOUserClient::clientClose( void ) @@ -1365,17 +1621,21 @@ IOMemoryMap * IOUserClient::mapClientMemory64( { IOReturn err; IOOptionBits options = 0; - IOMemoryDescriptor * memory; + IOMemoryDescriptor * memory = 0; IOMemoryMap * map = 0; err = clientMemoryForType( (UInt32) type, &options, &memory ); if( memory && (kIOReturnSuccess == err)) { + FAKE_STACK_FRAME(getMetaClass()); + options = (options & ~kIOMapUserOptionsMask) | (mapFlags & kIOMapUserOptionsMask); map = memory->createMappingInTask( task, atAddress, options ); memory->release(); + + FAKE_STACK_FRAME_END(); } return( map ); @@ -1389,9 +1649,41 @@ IOReturn IOUserClient::exportObjectToClient(task_t task, name = IOMachPort::makeSendRightForTask( task, obj, IKOT_IOKIT_OBJECT ); *(mach_port_name_t *)clientObj = name; + + if (obj) obj->release(); + + return kIOReturnSuccess; +} + +IOReturn IOUserClient::copyPortNameForObjectInTask(task_t task, + OSObject *obj, mach_port_name_t * port_name) +{ + mach_port_name_t name; + + name = IOMachPort::makeSendRightForTask( task, obj, IKOT_IOKIT_IDENT ); + + *(mach_port_name_t *) port_name = name; + return kIOReturnSuccess; } +IOReturn IOUserClient::copyObjectForPortNameInTask(task_t task, mach_port_name_t port_name, + OSObject **obj) +{ + OSObject * object; + + object = iokit_lookup_object_with_port_name(port_name, IKOT_IOKIT_IDENT, task); + + *obj = object; + + return (object ? kIOReturnSuccess : kIOReturnIPCError); +} + +IOReturn IOUserClient::adjustPortNameReferencesInTask(task_t task, mach_port_name_t port_name, mach_port_delta_t delta) +{ + return (iokit_mod_send_right(task, port_name, delta)); +} + IOExternalMethod * IOUserClient::getExternalMethodForIndex( UInt32 /* index */) { return( 0 ); @@ -1402,6 +1694,17 @@ IOExternalAsyncMethod * IOUserClient::getExternalAsyncMethodForIndex( UInt32 /* return( 0 ); } +IOExternalTrap * IOUserClient:: +getExternalTrapForIndex(UInt32 index) +{ + return NULL; +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +// Suppressing the deprecated-declarations warning. Avoiding the use of deprecated +// functions can break clients of kexts implementing getExternalMethodForIndex() IOExternalMethod * IOUserClient:: getTargetAndMethodForIndex(IOService **targetP, UInt32 index) { @@ -1424,12 +1727,6 @@ getAsyncTargetAndMethodForIndex(IOService ** targetP, UInt32 index) return method; } -IOExternalTrap * IOUserClient:: -getExternalTrapForIndex(UInt32 index) -{ - return NULL; -} - IOExternalTrap * IOUserClient:: getTargetAndTrapForIndex(IOService ** targetP, UInt32 index) { @@ -1441,6 +1738,7 @@ getTargetAndTrapForIndex(IOService ** targetP, UInt32 index) return trap; } +#pragma clang diagnostic pop IOReturn IOUserClient::releaseAsyncReference64(OSAsyncReference64 reference) { @@ -1526,6 +1824,7 @@ IOReturn IOUserClient::_sendAsyncResult64(OSAsyncReference64 reference, if (numArgs > kMaxAsyncArgs) return kIOReturnMessageTooLarge; + bzero(&replyMsg, sizeof(replyMsg)); replyMsg.msgHdr.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND /*remote*/, 0 /*local*/); replyMsg.msgHdr.msgh_remote_port = replyPort; @@ -1574,8 +1873,11 @@ IOReturn IOUserClient::_sendAsyncResult64(OSAsyncReference64 reference, kr = mach_msg_send_from_kernel_proper( &replyMsg.msgHdr, replyMsg.msgHdr.msgh_size); } - if ((KERN_SUCCESS != kr) && (MACH_SEND_TIMED_OUT != kr)) - IOLog("%s: mach_msg_send_from_kernel_proper {%x}\n", __FILE__, kr ); + if ((KERN_SUCCESS != kr) && (MACH_SEND_TIMED_OUT != kr) && !(kIOUCAsyncErrorLoggedFlag & reference[0])) + { + reference[0] |= kIOUCAsyncErrorLoggedFlag; + IOLog("%s: mach_msg_send_from_kernel_proper(0x%x)\n", __PRETTY_FUNCTION__, kr ); + } return kr; } @@ -1635,21 +1937,16 @@ kern_return_t is_io_object_get_class( io_name_t className ) { const OSMetaClass* my_obj = NULL; - const char * my_class_name = NULL; if( !object) return( kIOReturnBadArgument ); - if ( !my_class_name ) { - my_obj = object->getMetaClass(); - if (!my_obj) { - return (kIOReturnNotFound); - } - - my_class_name = my_obj->getClassName(); + my_obj = object->getMetaClass(); + if (!my_obj) { + return (kIOReturnNotFound); } - - strlcpy( className, my_class_name, sizeof(io_name_t)); + + strlcpy( className, my_obj->getClassName(), sizeof(io_name_t)); return( kIOReturnSuccess ); } @@ -1660,38 +1957,36 @@ kern_return_t is_io_object_get_superclass( io_name_t obj_name, io_name_t class_name) { - const OSMetaClass* my_obj = NULL; - const OSMetaClass* superclass = NULL; - const OSSymbol *my_name = NULL; - const char *my_cstr = NULL; + IOReturn ret; + const OSMetaClass * meta; + const OSMetaClass * super; + const OSSymbol * name; + const char * cstr; - if (!obj_name || !class_name) - return (kIOReturnBadArgument); + if (!obj_name || !class_name) return (kIOReturnBadArgument); + if (master_port != master_device_port) return( kIOReturnNotPrivileged); - if( master_port != master_device_port) - return( kIOReturnNotPrivileged); + ret = kIOReturnNotFound; + meta = 0; + do + { + name = OSSymbol::withCString(obj_name); + if (!name) break; + meta = OSMetaClass::copyMetaClassWithName(name); + if (!meta) break; + super = meta->getSuperClass(); + if (!super) break; + cstr = super->getClassName(); + if (!cstr) break; + strlcpy(class_name, cstr, sizeof(io_name_t)); + ret = kIOReturnSuccess; + } + while (false); - my_name = OSSymbol::withCString(obj_name); - - if (my_name) { - my_obj = OSMetaClass::getMetaClassWithName(my_name); - my_name->release(); - } - if (my_obj) { - superclass = my_obj->getSuperClass(); - } - - if (!superclass) { - return( kIOReturnNotFound ); - } + OSSafeReleaseNULL(name); + if (meta) meta->releaseMetaClass(); - my_cstr = superclass->getClassName(); - - if (my_cstr) { - strlcpy(class_name, my_cstr, sizeof(io_name_t)); - return( kIOReturnSuccess ); - } - return (kIOReturnNotFound); + return (ret); } /* Routine io_object_get_bundle_identifier */ @@ -1700,38 +1995,36 @@ kern_return_t is_io_object_get_bundle_identifier( io_name_t obj_name, io_name_t bundle_name) { - const OSMetaClass* my_obj = NULL; - const OSSymbol *my_name = NULL; - const OSSymbol *identifier = NULL; - const char *my_cstr = NULL; + IOReturn ret; + const OSMetaClass * meta; + const OSSymbol * name; + const OSSymbol * identifier; + const char * cstr; - if (!obj_name || !bundle_name) - return (kIOReturnBadArgument); + if (!obj_name || !bundle_name) return (kIOReturnBadArgument); + if (master_port != master_device_port) return( kIOReturnNotPrivileged); - if( master_port != master_device_port) - return( kIOReturnNotPrivileged); - - my_name = OSSymbol::withCString(obj_name); - - if (my_name) { - my_obj = OSMetaClass::getMetaClassWithName(my_name); - my_name->release(); - } + ret = kIOReturnNotFound; + meta = 0; + do + { + name = OSSymbol::withCString(obj_name); + if (!name) break; + meta = OSMetaClass::copyMetaClassWithName(name); + if (!meta) break; + identifier = meta->getKmodName(); + if (!identifier) break; + cstr = identifier->getCStringNoCopy(); + if (!cstr) break; + strlcpy(bundle_name, identifier->getCStringNoCopy(), sizeof(io_name_t)); + ret = kIOReturnSuccess; + } + while (false); - if (my_obj) { - identifier = my_obj->getKmodName(); - } - if (!identifier) { - return( kIOReturnNotFound ); - } - - my_cstr = identifier->getCStringNoCopy(); - if (my_cstr) { - strlcpy(bundle_name, identifier->getCStringNoCopy(), sizeof(io_name_t)); - return( kIOReturnSuccess ); - } + OSSafeReleaseNULL(name); + if (meta) meta->releaseMetaClass(); - return (kIOReturnBadArgument); + return (ret); } /* Routine io_object_conforms_to */ @@ -1767,12 +2060,24 @@ kern_return_t is_io_iterator_next( { IOReturn ret; OSObject * obj; + OSIterator * iter; + IOUserIterator * uiter; - CHECK( OSIterator, iterator, iter ); + if ((uiter = OSDynamicCast(IOUserIterator, iterator))) + { + obj = uiter->copyNextObject(); + } + else if ((iter = OSDynamicCast(OSIterator, iterator))) + { + obj = iter->getNextObject(); + if (obj) obj->retain(); + } + else + { + return( kIOReturnBadArgument ); + } - obj = iter->getNextObject(); if( obj) { - obj->retain(); *object = obj; ret = kIOReturnSuccess; } else @@ -1817,10 +2122,10 @@ static kern_return_t internal_io_service_match_property_table( OSObject * obj; OSDictionary * dict; - obj = matching_size ? OSUnserializeXML(matching, matching_size) - : OSUnserializeXML(matching); - if( (dict = OSDynamicCast( OSDictionary, obj))) { + assert(matching_size); + obj = OSUnserializeXML(matching, matching_size); + if( (dict = OSDynamicCast( OSDictionary, obj))) { *matches = service->passiveMatch( dict ); kr = kIOReturnSuccess; } else @@ -1838,7 +2143,7 @@ kern_return_t is_io_service_match_property_table( io_string_t matching, boolean_t *matches ) { - return (internal_io_service_match_property_table(service, matching, 0, matches)); + return (kIOReturnUnsupported); } @@ -1890,8 +2195,9 @@ static kern_return_t internal_io_service_get_matching_services( if( master_port != master_device_port) return( kIOReturnNotPrivileged); - obj = matching_size ? OSUnserializeXML(matching, matching_size) - : OSUnserializeXML(matching); + assert(matching_size); + obj = OSUnserializeXML(matching, matching_size); + if( (dict = OSDynamicCast( OSDictionary, obj))) { *existing = IOUserIterator::withIterator(IOService::getMatchingServices( dict )); kr = kIOReturnSuccess; @@ -1910,7 +2216,7 @@ kern_return_t is_io_service_get_matching_services( io_string_t matching, io_iterator_t *existing ) { - return (internal_io_service_get_matching_services(master_port, matching, 0, existing)); + return (kIOReturnUnsupported); } /* Routine io_service_get_matching_services_ool */ @@ -1930,6 +2236,8 @@ kern_return_t is_io_service_get_matching_services_ool( if( KERN_SUCCESS == kr) { // must return success after vm_map_copyout() succeeds + // and mig will copy out objects on success + *existing = 0; *result = internal_io_service_get_matching_services(master_port, (const char *) data, matchingCnt, existing); vm_deallocate( kernel_map, data, matchingCnt ); @@ -1962,8 +2270,9 @@ static kern_return_t internal_io_service_get_matching_service( if( master_port != master_device_port) return( kIOReturnNotPrivileged); - obj = matching_size ? OSUnserializeXML(matching, matching_size) - : OSUnserializeXML(matching); + assert(matching_size); + obj = OSUnserializeXML(matching, matching_size); + if( (dict = OSDynamicCast( OSDictionary, obj))) { *service = IOService::copyMatchingService( dict ); kr = *service ? kIOReturnSuccess : kIOReturnNotFound; @@ -1982,7 +2291,7 @@ kern_return_t is_io_service_get_matching_service( io_string_t matching, io_service_t *service ) { - return (internal_io_service_get_matching_service(master_port, matching, 0, service)); + return (kIOReturnUnsupported); } /* Routine io_service_get_matching_services_ool */ @@ -2002,6 +2311,8 @@ kern_return_t is_io_service_get_matching_service_ool( if( KERN_SUCCESS == kr) { // must return success after vm_map_copyout() succeeds + // and mig will copy out objects on success + *service = 0; *result = internal_io_service_get_matching_service(master_port, (const char *) data, matchingCnt, service ); vm_deallocate( kernel_map, data, matchingCnt ); @@ -2044,18 +2355,13 @@ static kern_return_t internal_io_service_add_notification( do { err = kIOReturnNoResources; + if (matching_size > (sizeof(io_struct_inband_t) * 1024)) return(kIOReturnMessageTooLarge); + if( !(sym = OSSymbol::withCString( notification_type ))) err = kIOReturnNoResources; - if (matching_size) - { - dict = OSDynamicCast(OSDictionary, OSUnserializeXML(matching, matching_size)); - } - else - { - dict = OSDynamicCast(OSDictionary, OSUnserializeXML(matching)); - } - + assert(matching_size); + dict = OSDynamicCast(OSDictionary, OSUnserializeXML(matching, matching_size)); if (!dict) { err = kIOReturnBadArgument; continue; @@ -2067,7 +2373,8 @@ static kern_return_t internal_io_service_add_notification( else if( (sym == gIOMatchedNotification) || (sym == gIOFirstMatchNotification)) userMsgType = kIOServiceMatchedNotificationType; - else if( sym == gIOTerminatedNotification) + else if ((sym == gIOTerminatedNotification) + || (sym == gIOWillTerminateNotification)) userMsgType = kIOServiceTerminatedNotificationType; else userMsgType = kLastIOKitNotificationType; @@ -2076,7 +2383,6 @@ static kern_return_t internal_io_service_add_notification( if( userNotify && !userNotify->init( port, userMsgType, reference, referenceSize, client64)) { - iokit_release_port_send(port); userNotify->release(); userNotify = 0; } @@ -2094,6 +2400,13 @@ static kern_return_t internal_io_service_add_notification( } while( false ); + if ((kIOReturnSuccess != err) && userNotify) + { + userNotify->invalidatePort(); + userNotify->release(); + userNotify = 0; + } + if( sym) sym->release(); if( dict) @@ -2113,9 +2426,7 @@ kern_return_t is_io_service_add_notification( mach_msg_type_number_t referenceCnt, io_object_t * notification ) { - return (internal_io_service_add_notification(master_port, notification_type, - matching, 0, port, &reference[0], sizeof(io_async_ref_t), - false, notification)); + return (kIOReturnUnsupported); } /* Routine io_service_add_notification_64 */ @@ -2128,9 +2439,7 @@ kern_return_t is_io_service_add_notification_64( mach_msg_type_number_t referenceCnt, io_object_t *notification ) { - return (internal_io_service_add_notification(master_port, notification_type, - matching, 0, wake_port, &reference[0], sizeof(io_async_ref64_t), - true, notification)); + return (kIOReturnUnsupported); } /* Routine io_service_add_notification_bin */ @@ -2188,6 +2497,8 @@ static kern_return_t internal_io_service_add_notification_ool( if( KERN_SUCCESS == kr) { // must return success after vm_map_copyout() succeeds + // and mig will copy out objects on success + *notification = 0; *result = internal_io_service_add_notification( master_port, notification_type, (char *) data, matchingCnt, wake_port, reference, referenceSize, client64, notification ); vm_deallocate( kernel_map, data, matchingCnt ); @@ -2271,7 +2582,6 @@ static kern_return_t internal_io_service_add_interest_notification( reference, referenceSize, kIOUserNotifyMaxMessageSize, client64 )) { - iokit_release_port_send(port); userNotify->release(); userNotify = 0; } @@ -2291,6 +2601,13 @@ static kern_return_t internal_io_service_add_interest_notification( } while( false ); + if ((kIOReturnSuccess != err) && userNotify) + { + userNotify->invalidatePort(); + userNotify->release(); + userNotify = 0; + } + return( err ); } @@ -2662,6 +2979,7 @@ kern_return_t is_io_registry_entry_get_property_bytes( if( (data = OSDynamicCast( OSData, obj ))) { len = data->getLength(); bytes = data->getBytesNoCopy(); + if (!data->isSerializable()) len = 0; } else if( (str = OSDynamicCast( OSString, obj ))) { len = str->getLength() + 1; @@ -2674,6 +2992,7 @@ kern_return_t is_io_registry_entry_get_property_bytes( } else if( (off = OSDynamicCast( OSNumber, obj ))) { offsetBytes = off->unsigned64BitValue(); len = off->numberOfBytes(); + if (len > sizeof(offsetBytes)) len = sizeof(offsetBytes); bytes = &offsetBytes; #ifdef __BIG_ENDIAN__ bytes = (const void *) @@ -2760,7 +3079,7 @@ kern_return_t is_io_registry_entry_get_property_recursively( #endif obj = entry->copyProperty( property_name, - IORegistryEntry::getPlane( plane ), options); + IORegistryEntry::getPlane( plane ), options ); if( !obj) return( kIOReturnNotFound ); @@ -2784,86 +3103,13 @@ kern_return_t is_io_registry_entry_get_property_recursively( return( err ); } -#if CONFIG_MACF - -static kern_return_t -filteredProperties(IORegistryEntry *entry, OSDictionary *properties, OSDictionary **filteredp) -{ - kern_return_t err = 0; - OSDictionary *filtered = NULL; - OSCollectionIterator *iter = NULL; - OSSymbol *key; - OSObject *p; - kauth_cred_t cred = kauth_cred_get(); - - if (properties == NULL) - return kIOReturnUnsupported; - - if ((iter = OSCollectionIterator::withCollection(properties)) == NULL || - (filtered = OSDictionary::withCapacity(properties->getCapacity())) == NULL) { - err = kIOReturnNoMemory; - goto out; - } - - while ((p = iter->getNextObject()) != NULL) { - if ((key = OSDynamicCast(OSSymbol, p)) == NULL || - mac_iokit_check_get_property(cred, entry, key->getCStringNoCopy()) != 0) - continue; - filtered->setObject(key, properties->getObject(key)); - } - -out: - if (iter != NULL) - iter->release(); - *filteredp = filtered; - return err; -} - -#endif - /* Routine io_registry_entry_get_properties */ kern_return_t is_io_registry_entry_get_properties( io_object_t registry_entry, io_buf_ptr_t *properties, mach_msg_type_number_t *propertiesCnt ) { - kern_return_t err = 0; - vm_size_t len; - - CHECK( IORegistryEntry, registry_entry, entry ); - - OSSerialize * s = OSSerialize::withCapacity(4096); - if( !s) - return( kIOReturnNoMemory ); - - if (!entry->serializeProperties(s)) - err = kIOReturnUnsupported; - -#if CONFIG_MACF - if (!err && mac_iokit_check_filter_properties(kauth_cred_get(), entry)) { - OSObject *propobj = OSUnserializeXML(s->text(), s->getLength()); - OSDictionary *filteredprops = NULL; - err = filteredProperties(entry, OSDynamicCast(OSDictionary, propobj), &filteredprops); - if (propobj) propobj->release(); - - if (!err) { - s->clearText(); - if (!filteredprops->serialize(s)) - err = kIOReturnUnsupported; - } - if (filteredprops != NULL) - filteredprops->release(); - } -#endif /* CONFIG_MACF */ - - if (!err) { - len = s->getLength(); - *propertiesCnt = len; - err = copyoutkdata( s->text(), len, properties ); - } - - s->release(); - return( err ); + return (kIOReturnUnsupported); } #if CONFIG_MACF @@ -2886,13 +3132,13 @@ GetPropertiesEditor(void * reference, if (!ref->root) ref->root = container; if (ref->root == container) - { - if (0 != mac_iokit_check_get_property(ref->cred, ref->entry, name->getCStringNoCopy())) - { - value = 0; - } - } - if (value) value->retain(); + { + if (0 != mac_iokit_check_get_property(ref->cred, ref->entry, name->getCStringNoCopy())) + { + value = 0; + } + } + if (value) value->retain(); return (value); } @@ -2931,9 +3177,9 @@ kern_return_t is_io_registry_entry_get_properties_bin( if (kIOReturnSuccess == err) { - len = s->getLength(); - *propertiesCnt = len; - err = copyoutkdata(s->text(), len, properties); + len = s->getLength(); + *propertiesCnt = len; + err = copyoutkdata(s->text(), len, properties); } s->release(); @@ -2961,25 +3207,29 @@ kern_return_t is_io_registry_entry_get_property_bin( return kIOReturnNotPermitted; #endif - if ((kIORegistryIterateRecursively & options) && plane[0]) + sym = OSSymbol::withCString(property_name); + if (!sym) return (kIOReturnNoMemory); + + if (gIORegistryEntryPropertyKeysKey == sym) { - obj = entry->copyProperty(property_name, - IORegistryEntry::getPlane(plane), options); + obj = entry->copyPropertyKeys(); } else { - obj = entry->copyProperty(property_name); + if ((kIORegistryIterateRecursively & options) && plane[0]) + { + obj = entry->copyProperty(property_name, + IORegistryEntry::getPlane(plane), options ); + } + else + { + obj = entry->copyProperty(property_name); + } + if (obj && gIORemoveOnReadProperties->containsObject(sym)) entry->removeProperty(sym); } - if( !obj) - return( kIOReturnNotFound ); - - sym = OSSymbol::withCString(property_name); - if (sym) - { - if (gIORemoveOnReadProperties->containsObject(sym)) entry->removeProperty(sym); - sym->release(); - } + sym->release(); + if (!obj) return (kIOReturnNotFound); OSSerialize * s = OSSerialize::binaryWithCapacity(4096); if( !s) { @@ -3025,6 +3275,8 @@ kern_return_t is_io_registry_entry_set_properties if( KERN_SUCCESS == err) { + FAKE_STACK_FRAME(entry->getMetaClass()); + // must return success after vm_map_copyout() succeeds obj = OSUnserializeXML( (const char *) data, propertiesCnt ); vm_deallocate( kernel_map, data, propertiesCnt ); @@ -3045,6 +3297,9 @@ kern_return_t is_io_registry_entry_set_properties if (obj) obj->release(); + + FAKE_STACK_FRAME_END(); + } else res = err; @@ -3060,8 +3315,8 @@ kern_return_t is_io_registry_entry_get_child_iterator( { CHECK( IORegistryEntry, registry_entry, entry ); - *iterator = entry->getChildIterator( - IORegistryEntry::getPlane( plane )); + *iterator = IOUserIterator::withIterator(entry->getChildIterator( + IORegistryEntry::getPlane( plane ))); return( kIOReturnSuccess ); } @@ -3074,8 +3329,8 @@ kern_return_t is_io_registry_entry_get_parent_iterator( { CHECK( IORegistryEntry, registry_entry, entry ); - *iterator = entry->getParentIterator( - IORegistryEntry::getPlane( plane )); + *iterator = IOUserIterator::withIterator(entry->getParentIterator( + IORegistryEntry::getPlane( plane ))); return( kIOReturnSuccess ); } @@ -3183,11 +3438,14 @@ kern_return_t is_io_service_open_extended( CHECK( IOService, _service, service ); - if (!owningTask) return (kIOReturnBadArgument); + if (!owningTask) return (kIOReturnBadArgument); + assert(owningTask == current_task()); + if (owningTask != current_task()) return (kIOReturnBadArgument); do { - if (properties) + if (properties) return (kIOReturnUnsupported); +#if 0 { OSObject * obj; vm_offset_t data; @@ -3215,7 +3473,7 @@ kern_return_t is_io_service_open_extended( if (kIOReturnSuccess != res) break; } - +#endif crossEndian = (ndr.int_rep != NDR_record.int_rep); if (crossEndian) { @@ -3240,6 +3498,10 @@ kern_return_t is_io_service_open_extended( { assert( OSDynamicCast(IOUserClient, client) ); + client->sharedInstance = (0 != client->getProperty(kIOUserClientSharedInstanceKey)); + client->closed = false; + client->lock = IOLockAlloc(); + disallowAccess = (crossEndian && (kOSBooleanTrue != service->getProperty(kIOUserClientCrossEndianCompatibleKey)) && (kOSBooleanTrue != client->getProperty(kIOUserClientCrossEndianCompatibleKey))); @@ -3248,6 +3510,9 @@ kern_return_t is_io_service_open_extended( else if (0 != mac_iokit_check_open(kauth_cred_get(), client, connect_type)) res = kIOReturnNotPermitted; #endif + + if (kIOReturnSuccess == res) res = client->registerOwner(owningTask); + if (kIOReturnSuccess != res) { IOStatisticsClientCall(); @@ -3256,7 +3521,6 @@ kern_return_t is_io_service_open_extended( client = 0; break; } - client->sharedInstance = (0 != client->getProperty(kIOUserClientSharedInstanceKey)); OSString * creatorName = IOCopyLogNameForPID(proc_selfpid()); if (creatorName) { @@ -3285,7 +3549,18 @@ kern_return_t is_io_service_close( CHECK( IOUserClient, connection, client ); IOStatisticsClientCall(); - client->clientClose(); + + if (client->sharedInstance || OSCompareAndSwap8(0, 1, &client->closed)) + { + IOLockLock(client->lock); + client->clientClose(); + IOLockUnlock(client->lock); + } + else + { + IOLog("ignored is_io_service_close(0x%qx,%s)\n", + client->getRegistryEntryID(), client->getName()); + } return( kIOReturnSuccess ); } @@ -3315,11 +3590,15 @@ kern_return_t is_io_connect_set_notification_port( mach_port_t port, uint32_t reference) { + kern_return_t ret; CHECK( IOUserClient, connection, client ); IOStatisticsClientCall(); - return( client->registerNotificationPort( port, notification_type, - (io_user_reference_t) reference )); + IOLockLock(client->lock); + ret = client->registerNotificationPort( port, notification_type, + (io_user_reference_t) reference ); + IOLockUnlock(client->lock); + return (ret); } /* Routine io_connect_set_notification_port */ @@ -3329,11 +3608,15 @@ kern_return_t is_io_connect_set_notification_port_64( mach_port_t port, io_user_reference_t reference) { + kern_return_t ret; CHECK( IOUserClient, connection, client ); IOStatisticsClientCall(); - return( client->registerNotificationPort( port, notification_type, - reference )); + IOLockLock(client->lock); + ret = client->registerNotificationPort( port, notification_type, + reference ); + IOLockUnlock(client->lock); + return (ret); } /* Routine io_connect_map_memory_into_task */ @@ -3369,6 +3652,7 @@ kern_return_t is_io_connect_map_memory_into_task mach_port_name_t name __unused = IOMachPort::makeSendRightForTask( into_task, map, IKOT_IOKIT_OBJECT ); + map->release(); } else { // keep it with the user client @@ -3453,7 +3737,7 @@ kern_return_t is_io_connect_unmap_memory_from_task { IOReturn err; IOOptionBits options = 0; - IOMemoryDescriptor * memory; + IOMemoryDescriptor * memory = 0; IOMemoryMap * map; CHECK( IOUserClient, connection, client ); @@ -3479,7 +3763,11 @@ kern_return_t is_io_connect_unmap_memory_from_task mach_port_name_t name = 0; if (from_task != current_task()) + { name = IOMachPort::makeSendRightForTask( from_task, map, IKOT_IOKIT_OBJECT ); + map->release(); + } + if (name) { map->userClientUnmap(); @@ -3565,6 +3853,7 @@ kern_return_t is_io_connect_method_var_output OSObject * structureVariableOutputData = 0; bzero(&args.__reserved[0], sizeof(args.__reserved)); + args.__reservedA = 0; args.version = kIOExternalMethodArgumentsCurrentVersion; args.selector = selector; @@ -3579,9 +3868,12 @@ kern_return_t is_io_connect_method_var_output args.structureInput = inband_input; args.structureInputSize = inband_inputCnt; + if (ool_input && (ool_input_size <= sizeof(io_struct_inband_t))) return (kIOReturnIPCError); + if (ool_input) inputMD = IOMemoryDescriptor::withAddressRange(ool_input, ool_input_size, - kIODirectionOut, current_task()); + kIODirectionOut | kIOMemoryMapCopyOnWrite, + current_task()); args.structureInputDescriptor = inputMD; @@ -3658,6 +3950,7 @@ kern_return_t is_io_connect_method IOMemoryDescriptor * outputMD = 0; bzero(&args.__reserved[0], sizeof(args.__reserved)); + args.__reservedA = 0; args.version = kIOExternalMethodArgumentsCurrentVersion; args.selector = selector; @@ -3672,9 +3965,13 @@ kern_return_t is_io_connect_method args.structureInput = inband_input; args.structureInputSize = inband_inputCnt; + 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_input) inputMD = IOMemoryDescriptor::withAddressRange(ool_input, ool_input_size, - kIODirectionOut, current_task()); + kIODirectionOut | kIOMemoryMapCopyOnWrite, + current_task()); args.structureInputDescriptor = inputMD; @@ -3738,6 +4035,7 @@ kern_return_t is_io_connect_async_method IOMemoryDescriptor * outputMD = 0; bzero(&args.__reserved[0], sizeof(args.__reserved)); + args.__reservedA = 0; args.version = kIOExternalMethodArgumentsCurrentVersion; reference[0] = (io_user_reference_t) wake_port; @@ -3750,14 +4048,20 @@ kern_return_t is_io_connect_async_method args.asyncReference = reference; args.asyncReferenceCount = referenceCnt; + args.structureVariableOutputData = 0; + args.scalarInput = scalar_input; args.scalarInputCount = scalar_inputCnt; args.structureInput = inband_input; args.structureInputSize = inband_inputCnt; + 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_input) inputMD = IOMemoryDescriptor::withAddressRange(ool_input, ool_input_size, - kIODirectionOut, current_task()); + kIODirectionOut | kIOMemoryMapCopyOnWrite, + current_task()); args.structureInputDescriptor = inputMD; @@ -3843,12 +4147,14 @@ kern_return_t shim_io_connect_method_scalarI_scalarO( if( inputCount != method->count0) { - IOLog("%s: IOUserClient inputCount count mismatch\n", object->getName()); + IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0); + DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0); continue; } if( *outputCount != method->count1) { - IOLog("%s: IOUserClient outputCount count mismatch\n", object->getName()); + IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)*outputCount, (uint64_t)method->count1); + DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)*outputCount, uint64_t, (uint64_t)method->count1); continue; } @@ -4077,12 +4383,14 @@ kern_return_t shim_io_async_method_scalarI_scalarO( if( inputCount != method->count0) { - IOLog("%s: IOUserClient inputCount count mismatch\n", object->getName()); + IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0); + DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0); continue; } if( *outputCount != method->count1) { - IOLog("%s: IOUserClient outputCount count mismatch\n", object->getName()); + IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)*outputCount, (uint64_t)method->count1); + DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)*outputCount, uint64_t, (uint64_t)method->count1); continue; } @@ -4187,13 +4495,15 @@ kern_return_t shim_io_connect_method_scalarI_structureO( do { if( inputCount != method->count0) { - IOLog("%s: IOUserClient inputCount count mismatch\n", object->getName()); + IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0); + DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0); continue; } if( (kIOUCVariableStructureSize != method->count1) && (*outputCount != method->count1)) { - IOLog("%s: IOUserClient outputCount count mismatch\n", object->getName()); + IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)*outputCount, (uint64_t)method->count1, (uint64_t)kIOUCVariableStructureSize); + DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)*outputCount, uint64_t, (uint64_t)method->count1); continue; } @@ -4260,13 +4570,15 @@ kern_return_t shim_io_async_method_scalarI_structureO( do { if( inputCount != method->count0) { - IOLog("%s: IOUserClient inputCount count mismatch\n", object->getName()); + IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0); + DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0); continue; } if( (kIOUCVariableStructureSize != method->count1) && (*outputCount != method->count1)) { - IOLog("%s: IOUserClient outputCount count mismatch\n", object->getName()); + IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)*outputCount, (uint64_t)method->count1, (uint64_t)kIOUCVariableStructureSize); + DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)*outputCount, uint64_t, (uint64_t)method->count1); continue; } @@ -4358,13 +4670,15 @@ kern_return_t shim_io_connect_method_scalarI_structureI( { if (inputCount != method->count0) { - IOLog("%s: IOUserClient inputCount count mismatch\n", object->getName()); + IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0); + DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0); continue; } if( (kIOUCVariableStructureSize != method->count1) && (inputStructCount != method->count1)) { - IOLog("%s: IOUserClient outputCount count mismatch\n", object->getName()); + IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputStructCount, (uint64_t)method->count1, (uint64_t)kIOUCVariableStructureSize); + DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputStructCount, uint64_t, (uint64_t)method->count1); continue; } @@ -4434,13 +4748,15 @@ kern_return_t shim_io_async_method_scalarI_structureI( { if (inputCount != method->count0) { - IOLog("%s: IOUserClient inputCount count mismatch\n", object->getName()); + IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0); + DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0); continue; } if( (kIOUCVariableStructureSize != method->count1) && (inputStructCount != method->count1)) { - IOLog("%s: IOUserClient outputCount count mismatch\n", object->getName()); + IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputStructCount, (uint64_t)method->count1, (uint64_t)kIOUCVariableStructureSize); + DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputStructCount, uint64_t, (uint64_t)method->count1); continue; } @@ -4530,13 +4846,15 @@ kern_return_t shim_io_connect_method_structureI_structureO( if( (kIOUCVariableStructureSize != method->count0) && (inputCount != method->count0)) { - IOLog("%s: IOUserClient inputCount count mismatch\n", object->getName()); + IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0, (uint64_t)kIOUCVariableStructureSize); + DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0); continue; } if( (kIOUCVariableStructureSize != method->count1) && (*outputCount != method->count1)) { - IOLog("%s: IOUserClient outputCount count mismatch\n", object->getName()); + IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)*outputCount, (uint64_t)method->count1, (uint64_t)kIOUCVariableStructureSize); + DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)*outputCount, uint64_t, (uint64_t)method->count1); continue; } @@ -4584,13 +4902,15 @@ kern_return_t shim_io_async_method_structureI_structureO( if( (kIOUCVariableStructureSize != method->count0) && (inputCount != method->count0)) { - IOLog("%s: IOUserClient inputCount count mismatch\n", object->getName()); + IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0, (uint64_t)kIOUCVariableStructureSize); + DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0); continue; } if( (kIOUCVariableStructureSize != method->count1) && (*outputCount != method->count1)) { - IOLog("%s: IOUserClient outputCount count mismatch\n", object->getName()); + IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)*outputCount, (uint64_t)method->count1, (uint64_t)kIOUCVariableStructureSize); + DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)*outputCount, uint64_t, (uint64_t)method->count1); continue; } @@ -4615,6 +4935,10 @@ kern_return_t 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( mach_port_t master_port, @@ -4623,6 +4947,9 @@ kern_return_t is_io_catalog_send_data( mach_msg_type_number_t inDataCount, kern_return_t * result) { +#if NO_KEXTD + return kIOReturnNotPrivileged; +#else /* NO_KEXTD */ OSObject * obj = 0; vm_offset_t data; kern_return_t kr = kIOReturnError; @@ -4640,6 +4967,16 @@ kern_return_t is_io_catalog_send_data( return kIOReturnBadArgument; } + if (!IOTaskHasEntitlement(current_task(), "com.apple.rootless.kext-secure-management")) + { + OSString * taskName = IOCopyLogNameForPID(proc_selfpid()); + IOLog("IOCatalogueSendData(%s): Not entitled\n", taskName ? taskName->getCStringNoCopy() : ""); + OSSafeReleaseNULL(taskName); + // For now, fake success to not break applications relying on this function succeeding. + // See for more details. + return kIOReturnSuccess; + } + if (inData) { vm_map_offset_t map_data; @@ -4750,14 +5087,12 @@ kern_return_t is_io_catalog_send_data( case kIOCatalogKextdFinishedLaunching: { #if !NO_KEXTD - static bool clearedBusy = false; - - if (!clearedBusy) { + if (!gIOKextdClearedBusy) { IOService * serviceRoot = IOService::getServiceRoot(); if (serviceRoot) { IOServiceTrace(IOSERVICE_KEXTD_READY, 0, 0, 0, 0); serviceRoot->adjustBusy(-1); - clearedBusy = true; + gIOKextdClearedBusy = true; } } #endif @@ -4771,9 +5106,10 @@ kern_return_t is_io_catalog_send_data( } if (obj) obj->release(); - + *result = kr; return( KERN_SUCCESS); +#endif /* NO_KEXTD */ } /* Routine io_catalog_terminate */ @@ -4860,7 +5196,7 @@ kern_return_t is_io_catalog_get_data( vm_size_t size; size = s->getLength(); - kr = vm_allocate(kernel_map, &data, size, VM_FLAGS_ANYWHERE); + 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, @@ -4938,7 +5274,7 @@ kern_return_t iokit_user_client_trap(struct iokit_user_client_trap_args *args) IOUserClient *userClient; if ((userClient = OSDynamicCast(IOUserClient, - iokit_lookup_connect_ref_current_task((OSObject *)(args->userClientRef))))) { + iokit_lookup_connect_ref_current_task((mach_port_name_t)(uintptr_t)args->userClientRef)))) { IOExternalTrap *trap; IOService *target = NULL; @@ -4954,12 +5290,30 @@ kern_return_t iokit_user_client_trap(struct iokit_user_client_trap_args *args) } } - userClient->release(); + iokit_remove_connect_reference(userClient); } return result; } +/* Routine io_device_tree_entry_exists_with_name */ +kern_return_t is_io_device_tree_entry_exists_with_name( + mach_port_t master_port, + io_name_t name, + boolean_t *exists ) +{ + OSCollectionIterator *iter; + + if (master_port != master_device_port) + return (kIOReturnNotPrivileged); + + iter = IODTFindMatchingEntries(IORegistryEntry::getRegistryRoot(), kIODTRecursive, name); + *exists = iter && iter->getNextObject(); + OSSafeReleaseNULL(iter); + + return kIOReturnSuccess; +} + } /* extern "C" */ IOReturn IOUserClient::externalMethod( uint32_t selector, IOExternalMethodArguments * args, @@ -5118,7 +5472,6 @@ IOReturn IOUserClient::externalMethod( uint32_t selector, IOExternalMethodArgume return (err); } - #if __LP64__ OSMetaClassDefineReservedUnused(IOUserClient, 0); OSMetaClassDefineReservedUnused(IOUserClient, 1);