]> git.saurik.com Git - apple/xnu.git/blobdiff - iokit/Kernel/IOUserClient.cpp
xnu-4903.231.4.tar.gz
[apple/xnu.git] / iokit / Kernel / IOUserClient.cpp
index b16a516bb9c9838680ab1a570fa5a1eede4ec2f1..b99f027ddd6fa28a952469428e29dd759f473360 100644 (file)
@@ -40,6 +40,7 @@
 #include <IOKit/IOBSD.h>
 #include <IOKit/IOStatisticsPrivate.h>
 #include <IOKit/IOTimeStamp.h>
 #include <IOKit/IOBSD.h>
 #include <IOKit/IOStatisticsPrivate.h>
 #include <IOKit/IOTimeStamp.h>
+#include <IOKit/IODeviceTreeSupport.h>
 #include <IOKit/system.h>
 #include <libkern/OSDebug.h>
 #include <sys/proc.h>
 #include <IOKit/system.h>
 #include <libkern/OSDebug.h>
 #include <sys/proc.h>
@@ -124,45 +125,13 @@ do { \
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
-// 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 "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 );
-
-extern mach_port_name_t iokit_make_send_right( task_t task,
-                               io_object_t obj, ipc_kobject_type_t type );
-
-extern kern_return_t iokit_mod_send_right( task_t task, mach_port_name_t name, mach_port_delta_t delta );
-
-extern io_object_t iokit_lookup_connect_ref(io_object_t clientRef, ipc_space_t task);
-
-extern io_object_t iokit_lookup_connect_ref_current_task(io_object_t clientRef);
-
-extern ipc_port_t master_device_port;
-
-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 );
-
 #include <mach/mach_traps.h>
 #include <vm/vm_map.h>
 
 } /* extern "C" */
 
 #include <mach/mach_traps.h>
 #include <vm/vm_map.h>
 
 } /* extern "C" */
 
-
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
 // IOMachPort maps OSObjects to ports, avoiding adding an ivar to OSObject.
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
 // IOMachPort maps OSObjects to ports, avoiding adding an ivar to OSObject.
@@ -202,17 +171,28 @@ static IOLock *           gIOObjectPortLock;
 // not in dictForType() for debugging ease
 static OSDictionary *  gIOObjectPorts;
 static OSDictionary *  gIOConnectPorts;
 // 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;
 
 
 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 );
 
     if( 0 == *dict)
         *dict = OSDictionary::withCapacity( 1 );
@@ -403,6 +383,7 @@ public:
     virtual void reset() APPLE_KEXT_OVERRIDE;
     virtual bool isValid() APPLE_KEXT_OVERRIDE;
     virtual OSObject * getNextObject() APPLE_KEXT_OVERRIDE;
     virtual void reset() APPLE_KEXT_OVERRIDE;
     virtual bool isValid() APPLE_KEXT_OVERRIDE;
     virtual OSObject * getNextObject() APPLE_KEXT_OVERRIDE;
+    virtual OSObject * copyNextObject();
 };
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 };
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
@@ -491,11 +472,20 @@ IOUserIterator::isValid()
 OSObject *
 IOUserIterator::getNextObject()
 {
 OSObject *
 IOUserIterator::getNextObject()
 {
-    OSObject * ret;
+    assert(false);
+    return (NULL);
+}
+
+OSObject *
+IOUserIterator::copyNextObject()
+{
+    OSObject * ret = NULL;
 
     IOLockLock(lock);
 
     IOLockLock(lock);
-    assert(OSDynamicCast(OSIterator, userIteratorObject));
-    ret = ((OSIterator *)userIteratorObject)->getNextObject();
+    if (userIteratorObject) {
+        ret = ((OSIterator *)userIteratorObject)->getNextObject();
+        if (ret) ret->retain();
+    }
     IOLockUnlock(lock);
 
     return (ret);
     IOLockUnlock(lock);
 
     return (ret);
@@ -507,10 +497,19 @@ extern "C" {
 // functions called from osfmk/device/iokit_rpc.c
 
 void
 // 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
 }
 
 void
@@ -520,18 +519,6 @@ iokit_remove_reference( io_object_t obj )
        obj->release();
 }
 
        obj->release();
 }
 
-void
-iokit_add_connect_reference( io_object_t obj )
-{
-    IOUserClient * uc;
-
-    if (!obj) return;
-
-    if ((uc = OSDynamicCast(IOUserClient, obj))) OSIncrementAtomic(&uc->__ipc);
-
-    obj->retain();
-}
-
 void
 iokit_remove_connect_reference( io_object_t obj )
 {
 void
 iokit_remove_connect_reference( io_object_t obj )
 {
@@ -605,7 +592,9 @@ iokit_client_died( io_object_t obj, ipc_port_t /* port */,
        if( (client = OSDynamicCast( IOUserClient, obj )))
        {
            IOStatisticsClientCall();
        if( (client = OSDynamicCast( IOUserClient, obj )))
        {
            IOStatisticsClientCall();
+           IOLockLock(client->lock);
            client->clientDied();
            client->clientDied();
+           IOLockUnlock(client->lock);
         }
     }
     else if( IKOT_IOKIT_OBJECT == type)
         }
     }
     else if( IKOT_IOKIT_OBJECT == type)
@@ -637,7 +626,6 @@ class IOServiceUserNotification : public IOUserNotification
     PingMsg    *       pingMsg;
     vm_size_t          msgSize;
     OSArray    *       newSet;
     PingMsg    *       pingMsg;
     vm_size_t          msgSize;
     OSArray    *       newSet;
-    OSObject   *       lastEntry;
     bool               armed;
     bool                ipcLogged;
 
     bool               armed;
     bool                ipcLogged;
 
@@ -654,6 +642,7 @@ public:
     virtual bool handler( void * ref, IOService * newService );
 
     virtual OSObject * getNextObject() APPLE_KEXT_OVERRIDE;
     virtual bool handler( void * ref, IOService * newService );
 
     virtual OSObject * getNextObject() APPLE_KEXT_OVERRIDE;
+    virtual OSObject * copyNextObject() APPLE_KEXT_OVERRIDE;
 };
 
 class IOServiceMessageUserNotification : public IOUserNotification
 };
 
 class IOServiceMessageUserNotification : public IOUserNotification
@@ -691,6 +680,7 @@ public:
                               void * messageArgument, vm_size_t argSize );
 
     virtual OSObject * getNextObject() APPLE_KEXT_OVERRIDE;
                               void * messageArgument, vm_size_t argSize );
 
     virtual OSObject * getNextObject() APPLE_KEXT_OVERRIDE;
+    virtual OSObject * copyNextObject() APPLE_KEXT_OVERRIDE;
 };
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 };
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
@@ -797,11 +787,9 @@ void IOServiceUserNotification::free( void )
     PingMsg   *        _pingMsg;
     vm_size_t  _msgSize;
     OSArray   *        _newSet;
     PingMsg   *        _pingMsg;
     vm_size_t  _msgSize;
     OSArray   *        _newSet;
-    OSObject  *        _lastEntry;
 
     _pingMsg   = pingMsg;
     _msgSize   = msgSize;
 
     _pingMsg   = pingMsg;
     _msgSize   = msgSize;
-    _lastEntry = lastEntry;
     _newSet    = newSet;
 
     super::free();
     _newSet    = newSet;
 
     super::free();
@@ -813,9 +801,6 @@ void IOServiceUserNotification::free( void )
         IOFree(_pingMsg, _msgSize);
        }
 
         IOFree(_pingMsg, _msgSize);
        }
 
-    if( _lastEntry)
-        _lastEntry->release();
-
     if( _newSet)
         _newSet->release();
 }
     if( _newSet)
         _newSet->release();
 }
@@ -871,16 +856,19 @@ bool IOServiceUserNotification::handler( void * ref,
 
     return( true );
 }
 
     return( true );
 }
-
 OSObject * IOServiceUserNotification::getNextObject()
 OSObject * IOServiceUserNotification::getNextObject()
+{
+    assert(false);
+    return (NULL);
+}
+
+OSObject * IOServiceUserNotification::copyNextObject()
 {
     unsigned int       count;
     OSObject *         result;
 {
     unsigned int       count;
     OSObject *         result;
-    OSObject *         releaseEntry;
 
     IOLockLock(lock);
 
 
     IOLockLock(lock);
 
-    releaseEntry = lastEntry;
     count = newSet->getCount();
     if( count ) {
         result = newSet->getObject( count - 1 );
     count = newSet->getCount();
     if( count ) {
         result = newSet->getObject( count - 1 );
@@ -890,12 +878,9 @@ OSObject * IOServiceUserNotification::getNextObject()
         result = 0;
         armed = true;
     }
         result = 0;
         armed = true;
     }
-    lastEntry = result;
 
     IOLockUnlock(lock);
 
 
     IOLockUnlock(lock);
 
-    if (releaseEntry) releaseEntry->release();
-
     return( result );
 }
 
     return( result );
 }
 
@@ -1006,9 +991,9 @@ IOReturn IOServiceMessageUserNotification::handler( void * ref,
     }
     else
     {
     }
     else
     {
+        if( callerArgSize > kIOUserNotifyMaxMessageSize)
+            callerArgSize = kIOUserNotifyMaxMessageSize;
         argSize = callerArgSize;
         argSize = callerArgSize;
-        if( argSize > kIOUserNotifyMaxMessageSize)
-            argSize = kIOUserNotifyMaxMessageSize;
     }
 
     // adjust message size for ipc restrictions
     }
 
     // adjust message size for ipc restrictions
@@ -1089,6 +1074,11 @@ OSObject * IOServiceMessageUserNotification::getNextObject()
     return( 0 );
 }
 
     return( 0 );
 }
 
+OSObject * IOServiceMessageUserNotification::copyNextObject()
+{
+    return( NULL );
+}
+
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
 #undef super
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
 #undef super
@@ -1459,7 +1449,7 @@ IOUserClient::registerOwner(task_t task)
     if (newOwner)
     {
         owner = IONew(IOUserClientOwner, 1);
     if (newOwner)
     {
         owner = IONew(IOUserClientOwner, 1);
-        if (!newOwner) ret = kIOReturnNoMemory;
+        if (!owner) ret = kIOReturnNoMemory;
         else
         {
             owner->task = task;
         else
         {
             owner->task = task;
@@ -1544,6 +1534,7 @@ iokit_task_terminate(task_t task)
 void IOUserClient::free()
 {
     if( mappings) mappings->release();
 void IOUserClient::free()
 {
     if( mappings) mappings->release();
+    if (lock) IOLockFree(lock);
                
     IOStatisticsUnregisterCounter();
 
                
     IOStatisticsUnregisterCounter();
 
@@ -1658,9 +1649,41 @@ IOReturn IOUserClient::exportObjectToClient(task_t task,
     name = IOMachPort::makeSendRightForTask( task, obj, IKOT_IOKIT_OBJECT );
 
     *(mach_port_name_t *)clientObj = name;
     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;
 }
 
     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 );
 IOExternalMethod * IOUserClient::getExternalMethodForIndex( UInt32 /* index */)
 {
     return( 0 );
@@ -2037,12 +2060,24 @@ kern_return_t is_io_iterator_next(
 {
     IOReturn    ret;
     OSObject * obj;
 {
     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) {
     if( obj) {
-       obj->retain();
        *object = obj;
         ret = kIOReturnSuccess;
     } else
        *object = obj;
         ret = kIOReturnSuccess;
     } else
@@ -2320,6 +2355,8 @@ static kern_return_t internal_io_service_add_notification(
     do {
         err = kIOReturnNoResources;
 
     do {
         err = kIOReturnNoResources;
 
+        if (matching_size > (sizeof(io_struct_inband_t) * 1024)) return(kIOReturnMessageTooLarge);
+
         if( !(sym = OSSymbol::withCString( notification_type )))
            err = kIOReturnNoResources;
 
         if( !(sym = OSSymbol::withCString( notification_type )))
            err = kIOReturnNoResources;
 
@@ -3278,8 +3315,8 @@ kern_return_t is_io_registry_entry_get_child_iterator(
 {
     CHECK( IORegistryEntry, registry_entry, entry );
 
 {
     CHECK( IORegistryEntry, registry_entry, entry );
 
-    *iterator = entry->getChildIterator(
-    IORegistryEntry::getPlane( plane ));
+    *iterator = IOUserIterator::withIterator(entry->getChildIterator(
+    IORegistryEntry::getPlane( plane )));
 
     return( kIOReturnSuccess );
 }
 
     return( kIOReturnSuccess );
 }
@@ -3292,8 +3329,8 @@ kern_return_t is_io_registry_entry_get_parent_iterator(
 {
     CHECK( IORegistryEntry, registry_entry, entry );
 
 {
     CHECK( IORegistryEntry, registry_entry, entry );
 
-    *iterator = entry->getParentIterator(
-       IORegistryEntry::getPlane( plane ));
+    *iterator = IOUserIterator::withIterator(entry->getParentIterator(
+       IORegistryEntry::getPlane( plane )));
 
     return( kIOReturnSuccess );
 }
 
     return( kIOReturnSuccess );
 }
@@ -3463,6 +3500,7 @@ kern_return_t is_io_service_open_extended(
 
            client->sharedInstance = (0 != client->getProperty(kIOUserClientSharedInstanceKey));
            client->closed = false;
 
            client->sharedInstance = (0 != client->getProperty(kIOUserClientSharedInstanceKey));
            client->closed = false;
+           client->lock = IOLockAlloc();
 
            disallowAccess = (crossEndian
                && (kOSBooleanTrue != service->getProperty(kIOUserClientCrossEndianCompatibleKey))
 
            disallowAccess = (crossEndian
                && (kOSBooleanTrue != service->getProperty(kIOUserClientCrossEndianCompatibleKey))
@@ -3514,7 +3552,9 @@ kern_return_t is_io_service_close(
 
     if (client->sharedInstance || OSCompareAndSwap8(0, 1, &client->closed)) 
     {
 
     if (client->sharedInstance || OSCompareAndSwap8(0, 1, &client->closed)) 
     {
+       IOLockLock(client->lock);
        client->clientClose();
        client->clientClose();
+       IOLockUnlock(client->lock);
     }
     else
     {
     }
     else
     {
@@ -3550,11 +3590,15 @@ kern_return_t is_io_connect_set_notification_port(
        mach_port_t port,
        uint32_t reference)
 {
        mach_port_t port,
        uint32_t reference)
 {
+    kern_return_t ret;
     CHECK( IOUserClient, connection, client );
 
     IOStatisticsClientCall();
     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 */
 }
 
 /* Routine io_connect_set_notification_port */
@@ -3564,11 +3608,15 @@ kern_return_t is_io_connect_set_notification_port_64(
        mach_port_t port,
        io_user_reference_t reference)
 {
        mach_port_t port,
        io_user_reference_t reference)
 {
+    kern_return_t ret;
     CHECK( IOUserClient, connection, client );
 
     IOStatisticsClientCall();
     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 */
 }
 
 /* Routine io_connect_map_memory_into_task */
@@ -3604,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 );
            mach_port_name_t name __unused =
                IOMachPort::makeSendRightForTask(
                                     into_task, map, IKOT_IOKIT_OBJECT );
+           map->release();
 
         } else {
             // keep it with the user client
 
         } else {
             // keep it with the user client
@@ -3714,7 +3763,11 @@ kern_return_t is_io_connect_unmap_memory_from_task
 
            mach_port_name_t name = 0;
            if (from_task != current_task())
 
            mach_port_name_t name = 0;
            if (from_task != current_task())
+           {
                name = IOMachPort::makeSendRightForTask( from_task, map, IKOT_IOKIT_OBJECT );
                name = IOMachPort::makeSendRightForTask( from_task, map, IKOT_IOKIT_OBJECT );
+               map->release();
+           }
+
            if (name)
            {
                map->userClientUnmap();
            if (name)
            {
                map->userClientUnmap();
@@ -4914,7 +4967,7 @@ kern_return_t is_io_catalog_send_data(
         return kIOReturnBadArgument;
     }
 
         return kIOReturnBadArgument;
     }
 
-    if (!IOTaskHasEntitlement(current_task(), "com.apple.rootless.kext-management"))
+    if (!IOTaskHasEntitlement(current_task(), "com.apple.rootless.kext-secure-management"))
     {
         OSString * taskName = IOCopyLogNameForPID(proc_selfpid());
         IOLog("IOCatalogueSendData(%s): Not entitled\n", taskName ? taskName->getCStringNoCopy() : "");
     {
         OSString * taskName = IOCopyLogNameForPID(proc_selfpid());
         IOLog("IOCatalogueSendData(%s): Not entitled\n", taskName ? taskName->getCStringNoCopy() : "");
@@ -5221,7 +5274,7 @@ kern_return_t iokit_user_client_trap(struct iokit_user_client_trap_args *args)
     IOUserClient *userClient;
 
     if ((userClient = OSDynamicCast(IOUserClient,
     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;
 
         IOExternalTrap *trap;
         IOService *target = NULL;
 
@@ -5243,6 +5296,24 @@ kern_return_t iokit_user_client_trap(struct iokit_user_client_trap_args *args)
     return result;
 }
 
     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,
 } /* extern "C" */
 
 IOReturn IOUserClient::externalMethod( uint32_t selector, IOExternalMethodArguments * args,