]> git.saurik.com Git - apple/xnu.git/blobdiff - iokit/Kernel/IOUserClient.cpp
xnu-3248.20.55.tar.gz
[apple/xnu.git] / iokit / Kernel / IOUserClient.cpp
index 9f3587844c70067f063d0b33023290b3287e823b..8c628ddf1f83c7ee367a4c792fc1793ee69de629 100644 (file)
@@ -166,7 +166,7 @@ public:
     static mach_port_name_t makeSendRightForTask( task_t task,
                                io_object_t obj, ipc_kobject_type_t type );
 
-    virtual void free();
+    virtual void free() APPLE_KEXT_OVERRIDE;
 };
 
 #define super OSObject
@@ -354,24 +354,118 @@ void IOMachPort::free( void )
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
-class IOUserNotification : public OSIterator
+class IOUserIterator : public OSIterator
+{
+    OSDeclareDefaultStructors(IOUserIterator)
+public:
+    OSObject   *       userIteratorObject;
+    IOLock     *       lock;
+
+    static IOUserIterator * withIterator(OSIterator * iter);
+    virtual bool init( void ) APPLE_KEXT_OVERRIDE;
+    virtual void free() APPLE_KEXT_OVERRIDE;
+
+    virtual void reset() APPLE_KEXT_OVERRIDE;
+    virtual bool isValid() APPLE_KEXT_OVERRIDE;
+    virtual OSObject * getNextObject() APPLE_KEXT_OVERRIDE;
+};
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+class IOUserNotification : public IOUserIterator
 {
     OSDeclareDefaultStructors(IOUserNotification)
 
-    IONotifier         *       holdNotify;
-    IOLock     *       lock;
+#define holdNotify     userIteratorObject
 
 public:
 
-    virtual bool init( void );
-    virtual void free();
+    virtual void free() APPLE_KEXT_OVERRIDE;
 
     virtual void setNotification( IONotifier * obj );
 
-    virtual void reset();
-    virtual bool isValid();
+    virtual void reset() APPLE_KEXT_OVERRIDE;
+    virtual bool isValid() APPLE_KEXT_OVERRIDE;
 };
 
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+OSDefineMetaClassAndStructors( IOUserIterator, OSIterator )
+
+IOUserIterator *
+IOUserIterator::withIterator(OSIterator * iter)
+{
+    IOUserIterator * me;
+
+    if (!iter) return (0);
+
+    me = new IOUserIterator;
+    if (me && !me->init())
+    {
+       me->release();
+       me = 0;
+    }
+    if (!me) return me;
+    me->userIteratorObject = iter;
+
+    return (me);
+}
+
+bool
+IOUserIterator::init( void )
+{
+    if (!OSObject::init()) return (false);
+
+    lock = IOLockAlloc();
+    if( !lock)
+        return( false );
+
+    return (true);
+}
+
+void
+IOUserIterator::free()
+{
+    if (userIteratorObject) userIteratorObject->release();
+    if (lock) IOLockFree(lock);
+    OSObject::free();
+}
+
+void
+IOUserIterator::reset()
+{
+    IOLockLock(lock);
+    assert(OSDynamicCast(OSIterator, userIteratorObject));
+    ((OSIterator *)userIteratorObject)->reset();
+    IOLockUnlock(lock);
+}
+
+bool
+IOUserIterator::isValid()
+{
+    bool ret;
+
+    IOLockLock(lock);
+    assert(OSDynamicCast(OSIterator, userIteratorObject));
+    ret = ((OSIterator *)userIteratorObject)->isValid();
+    IOLockUnlock(lock);
+
+    return (ret);
+}
+
+OSObject *
+IOUserIterator::getNextObject()
+{
+    OSObject * ret;
+
+    IOLockLock(lock);
+    assert(OSDynamicCast(OSIterator, userIteratorObject));
+    ret = ((OSIterator *)userIteratorObject)->getNextObject();
+    IOLockUnlock(lock);
+
+    return (ret);
+}
+
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 extern "C" {
 
@@ -466,13 +560,13 @@ public:
     virtual bool init( mach_port_t port, natural_t type,
                        void * reference, vm_size_t referenceSize,
                       bool clientIs64 );
-    virtual void free();
+    virtual void free() APPLE_KEXT_OVERRIDE;
 
     static bool _handler( void * target,
                           void * ref, IOService * newService, IONotifier * notifier );
     virtual bool handler( void * ref, IOService * newService );
 
-    virtual OSObject * getNextObject();
+    virtual OSObject * getNextObject() APPLE_KEXT_OVERRIDE;
 };
 
 class IOServiceMessageUserNotification : public IOUserNotification
@@ -498,7 +592,7 @@ public:
                       vm_size_t extraSize,
                       bool clientIs64 );
 
-    virtual void free();
+    virtual void free() APPLE_KEXT_OVERRIDE;
     
     static IOReturn _handler( void * target, void * ref,
                               UInt32 messageType, IOService * provider,
@@ -507,46 +601,35 @@ public:
                               UInt32 messageType, IOService * provider,
                               void * messageArgument, vm_size_t argSize );
 
-    virtual OSObject * getNextObject();
+    virtual OSObject * getNextObject() APPLE_KEXT_OVERRIDE;
 };
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
 #undef super
-#define super OSIterator
-OSDefineMetaClass( IOUserNotification, OSIterator )
-OSDefineAbstractStructors( IOUserNotification, OSIterator )
+#define super IOUserIterator
+OSDefineMetaClass( IOUserNotification, IOUserIterator )
+OSDefineAbstractStructors( IOUserNotification, IOUserIterator )
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
-bool IOUserNotification::init( void )
-{
-    if( !super::init())
-       return( false );
-
-    lock = IOLockAlloc();
-    if( !lock)
-        return( false );
-
-    return( true );
-}
-
 void IOUserNotification::free( void )
 {
-    if( holdNotify)
-       holdNotify->remove();
+    if (holdNotify)
+    {
+       assert(OSDynamicCast(IONotifier, holdNotify));
+       ((IONotifier *)holdNotify)->remove();
+       holdNotify = 0;
+    }
     // can't be in handler now
 
-    if( lock)
-       IOLockFree( lock );
-
     super::free();
 }
 
 
 void IOUserNotification::setNotification( IONotifier * notify )
 {
-    IONotifier * previousNotify;
+    OSObject * previousNotify;
 
     IOLockLock( gIOObjectPortLock);
 
@@ -556,7 +639,10 @@ void IOUserNotification::setNotification( IONotifier * notify )
     IOLockUnlock( gIOObjectPortLock);
 
     if( previousNotify)
-       previousNotify->remove();
+    {
+       assert(OSDynamicCast(IONotifier, previousNotify));
+       ((IONotifier *)previousNotify)->remove();
+    }
 }
 
 void IOUserNotification::reset()
@@ -1503,6 +1589,35 @@ extern "C" {
        if( !(out = OSDynamicCast( cls, obj)))  \
            return( kIOReturnBadArgument )
 
+#define CHECKLOCKED(cls,obj,out)                                       \
+       IOUserIterator * oIter;                                         \
+       cls * out;                                                      \
+       if( !(oIter = OSDynamicCast(IOUserIterator, obj)))              \
+           return (kIOReturnBadArgument);                              \
+       if( !(out = OSDynamicCast(cls, oIter->userIteratorObject)))     \
+           return (kIOReturnBadArgument)
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+// Create a vm_map_copy_t or kalloc'ed data for memory
+// to be copied out. ipc will free after the copyout.
+
+static kern_return_t copyoutkdata( const void * data, vm_size_t len,
+                                    io_buf_ptr_t * buf )
+{
+    kern_return_t      err;
+    vm_map_copy_t      copy;
+
+    err = vm_map_copyin( kernel_map, CAST_USER_ADDR_T(data), len,
+                    false /* src_destroy */, &copy);
+
+    assert( err == KERN_SUCCESS );
+    if( err == KERN_SUCCESS )
+        *buf = (char *) copy;
+
+    return( err );
+}
+
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
 /* Routine io_server_version */
@@ -1516,20 +1631,26 @@ kern_return_t is_io_server_version(
 
 /* Routine io_object_get_class */
 kern_return_t is_io_object_get_class(
-       io_object_t object,
-       io_name_t className )
+    io_object_t object,
+    io_name_t className )
 {
-       const OSMetaClass* my_obj = NULL;
+    const OSMetaClass* my_obj = NULL;
+    const char * my_class_name = NULL;
        
-       if( !object)
-               return( kIOReturnBadArgument );
+    if( !object)
+        return( kIOReturnBadArgument );
                
-       my_obj = object->getMetaClass();
-       if (!my_obj) {
-               return (kIOReturnNotFound);
-       }
+    if ( !my_class_name ) {
+        my_obj = object->getMetaClass();
+        if (!my_obj) {
+            return (kIOReturnNotFound);
+        }
+
+        my_class_name = my_obj->getClassName();
+    }
        
-    strlcpy( className, my_obj->getClassName(), sizeof(io_name_t));
+    strlcpy( className, my_class_name, sizeof(io_name_t));
+
     return( kIOReturnSuccess );
 }
 
@@ -1623,6 +1744,7 @@ kern_return_t is_io_object_conforms_to(
         return( kIOReturnBadArgument );
 
     *conforms = (0 != object->metaCast( className ));
+
     return( kIOReturnSuccess );
 }
 
@@ -1643,6 +1765,7 @@ kern_return_t is_io_iterator_next(
        io_object_t iterator,
        io_object_t *object )
 {
+    IOReturn    ret;
     OSObject * obj;
 
     CHECK( OSIterator, iterator, iter );
@@ -1651,9 +1774,11 @@ kern_return_t is_io_iterator_next(
     if( obj) {
        obj->retain();
        *object = obj;
-        return( kIOReturnSuccess );
+        ret = kIOReturnSuccess;
     } else
-        return( kIOReturnNoDevice );
+        ret = kIOReturnNoDevice;
+
+    return (ret);
 }
 
 /* Routine io_iterator_reset */
@@ -1695,6 +1820,7 @@ static kern_return_t internal_io_service_match_property_table(
     obj = matching_size ? OSUnserializeXML(matching, matching_size)
                        : OSUnserializeXML(matching);
     if( (dict = OSDynamicCast( OSDictionary, obj))) {
+
         *matches = service->passiveMatch( dict );
        kr = kIOReturnSuccess;
     } else
@@ -1767,7 +1893,7 @@ static kern_return_t internal_io_service_get_matching_services(
     obj = matching_size ? OSUnserializeXML(matching, matching_size)
                        : OSUnserializeXML(matching);
     if( (dict = OSDynamicCast( OSDictionary, obj))) {
-        *existing = IOService::getMatchingServices( dict );
+        *existing = IOUserIterator::withIterator(IOService::getMatchingServices( dict ));
        kr = kIOReturnSuccess;
     } else
        kr = kIOReturnBadArgument;
@@ -2249,8 +2375,9 @@ kern_return_t is_io_registry_create_iterator(
     if( master_port != master_device_port)
         return( kIOReturnNotPrivileged);
 
-    *iterator = IORegistryIterator::iterateOver(
-       IORegistryEntry::getPlane( plane ), options );
+    *iterator = IOUserIterator::withIterator(
+       IORegistryIterator::iterateOver(
+               IORegistryEntry::getPlane( plane ), options ));
 
     return( *iterator ? kIOReturnSuccess : kIOReturnBadArgument );
 }
@@ -2264,8 +2391,9 @@ kern_return_t is_io_registry_entry_create_iterator(
 {
     CHECK( IORegistryEntry, registry_entry, entry );
 
-    *iterator = IORegistryIterator::iterateOver( entry,
-       IORegistryEntry::getPlane( plane ), options );
+    *iterator = IOUserIterator::withIterator(
+       IORegistryIterator::iterateOver( entry,
+               IORegistryEntry::getPlane( plane ), options ));
 
     return( *iterator ? kIOReturnSuccess : kIOReturnBadArgument );
 }
@@ -2274,9 +2402,11 @@ kern_return_t is_io_registry_entry_create_iterator(
 kern_return_t is_io_registry_iterator_enter_entry(
        io_object_t iterator )
 {
-    CHECK( IORegistryIterator, iterator, iter );
+    CHECKLOCKED( IORegistryIterator, iterator, iter );
 
+    IOLockLock(oIter->lock);
     iter->enterEntry();
+    IOLockUnlock(oIter->lock);
 
     return( kIOReturnSuccess );
 }
@@ -2287,9 +2417,11 @@ kern_return_t is_io_registry_iterator_exit_entry(
 {
     bool       didIt;
 
-    CHECK( IORegistryIterator, iterator, iter );
+    CHECKLOCKED( IORegistryIterator, iterator, iter );
 
+    IOLockLock(oIter->lock);
     didIt = iter->exitEntry();
+    IOLockUnlock(oIter->lock);
 
     return( didIt ? kIOReturnSuccess : kIOReturnNoDevice );
 }
@@ -2312,6 +2444,58 @@ kern_return_t is_io_registry_entry_from_path(
     return( kIOReturnSuccess );
 }
 
+
+/* Routine io_registry_entry_from_path */
+kern_return_t is_io_registry_entry_from_path_ool(
+       mach_port_t master_port,
+       io_string_inband_t path,
+       io_buf_ptr_t path_ool,
+       mach_msg_type_number_t path_oolCnt,
+       kern_return_t *result,
+       io_object_t *registry_entry)
+{
+    IORegistryEntry *  entry;
+    vm_map_offset_t    map_data;
+    const char *       cpath;
+    IOReturn            res;
+    kern_return_t       err;
+
+    if (master_port != master_device_port) return(kIOReturnNotPrivileged);
+
+    map_data = 0;
+    entry    = 0;
+    res = err = KERN_SUCCESS;
+    if (path[0]) cpath = path;
+    else
+    {
+       if (!path_oolCnt)                                      return(kIOReturnBadArgument);
+       if (path_oolCnt > (sizeof(io_struct_inband_t) * 1024)) return(kIOReturnMessageTooLarge);
+
+       err = vm_map_copyout(kernel_map, &map_data, (vm_map_copy_t) path_ool);
+       if (KERN_SUCCESS == err)
+       {
+           // must return success to mig after vm_map_copyout() succeeds, so result is actual
+           cpath = CAST_DOWN(const char *, map_data);
+           if (cpath[path_oolCnt - 1]) res = kIOReturnBadArgument;
+       }
+    }
+
+    if ((KERN_SUCCESS == err) && (KERN_SUCCESS == res))
+    {
+       entry = IORegistryEntry::fromPath(cpath);
+       res = entry ? kIOReturnSuccess : kIOReturnNotFound;
+    }
+
+    if (map_data) vm_deallocate(kernel_map, map_data, path_oolCnt);
+
+    if (KERN_SUCCESS != err) res = err;
+    *registry_entry = entry;
+    *result = res;
+
+    return (err);
+}
+
+
 /* Routine io_registry_entry_in_plane */
 kern_return_t is_io_registry_entry_in_plane(
        io_object_t registry_entry,
@@ -2342,6 +2526,42 @@ kern_return_t is_io_registry_entry_get_path(
        return( kIOReturnBadArgument );
 }
 
+/* Routine io_registry_entry_get_path */
+kern_return_t is_io_registry_entry_get_path_ool(
+       io_object_t registry_entry,
+       io_name_t plane,
+       io_string_inband_t path,
+       io_buf_ptr_t *path_ool,
+       mach_msg_type_number_t *path_oolCnt)
+{
+    enum   { kMaxPath = 16384 };
+    IOReturn err;
+    int      length;
+    char   * buf;
+
+    CHECK( IORegistryEntry, registry_entry, entry );
+
+    *path_ool    = NULL;
+    *path_oolCnt = 0;
+    length = sizeof(io_string_inband_t);
+    if (entry->getPath(path, &length, IORegistryEntry::getPlane(plane))) err = kIOReturnSuccess;
+    else
+    {
+       length = kMaxPath;
+       buf = IONew(char, length);
+       if (!buf) err = kIOReturnNoMemory;
+       else if (!entry->getPath(buf, &length, IORegistryEntry::getPlane(plane))) err = kIOReturnError;
+       else
+       {
+           *path_oolCnt = length;
+           err = copyoutkdata(buf, length, path_ool);
+       }
+       if (buf) IODelete(buf, char, kMaxPath);
+    }
+
+    return (err);
+}
+
 
 /* Routine io_registry_entry_get_name */
 kern_return_t is_io_registry_entry_get_name(
@@ -2409,25 +2629,6 @@ kern_return_t is_io_registry_entry_get_registry_entry_id(
     return (kIOReturnSuccess);
 }
 
-// Create a vm_map_copy_t or kalloc'ed data for memory
-// to be copied out. ipc will free after the copyout.
-
-static kern_return_t copyoutkdata( const void * data, vm_size_t len,
-                                    io_buf_ptr_t * buf )
-{
-    kern_return_t      err;
-    vm_map_copy_t      copy;
-
-    err = vm_map_copyin( kernel_map, CAST_USER_ADDR_T(data), len,
-                    false /* src_destroy */, &copy);
-
-    assert( err == KERN_SUCCESS );
-    if( err == KERN_SUCCESS )
-        *buf = (char *) copy;
-
-    return( err );
-}
-
 /* Routine io_registry_entry_get_property */
 kern_return_t is_io_registry_entry_get_property_bytes(
        io_object_t registry_entry,
@@ -2799,6 +3000,7 @@ kern_return_t is_io_registry_entry_get_property_bin(
     return( err );
 }
 
+
 /* Routine io_registry_entry_set_properties */
 kern_return_t is_io_registry_entry_set_properties
 (
@@ -2981,6 +3183,8 @@ kern_return_t is_io_service_open_extended(
 
     CHECK( IOService, _service, service );
 
+    if (!owningTask) return (kIOReturnBadArgument);
+
     do
     {
        if (properties)
@@ -3148,6 +3352,8 @@ kern_return_t is_io_connect_map_memory_into_task
 
     CHECK( IOUserClient, connection, client );
 
+    if (!into_task) return (kIOReturnBadArgument);
+
     IOStatisticsClientCall();
     map = client->mapClientMemory64( memory_type, into_task, flags, *address );
 
@@ -3252,6 +3458,8 @@ kern_return_t is_io_connect_unmap_memory_from_task
 
     CHECK( IOUserClient, connection, client );
 
+    if (!from_task) return (kIOReturnBadArgument);
+
     IOStatisticsClientCall();
     err = client->clientMemoryForType( (UInt32) memory_type, &options, &memory );
 
@@ -4148,8 +4356,7 @@ kern_return_t shim_io_connect_method_scalarI_structureI(
 
     do
     {
-       if( (kIOUCVariableStructureSize != method->count0)
-               && (inputCount != method->count0))
+       if (inputCount != method->count0)
        {
            IOLog("%s: IOUserClient inputCount count mismatch\n", object->getName());
            continue;
@@ -4225,8 +4432,7 @@ kern_return_t shim_io_async_method_scalarI_structureI(
 
     do
     {
-       if( (kIOUCVariableStructureSize != method->count0)
-               && (inputCount != method->count0))
+       if (inputCount != method->count0)
        {
            IOLog("%s: IOUserClient inputCount count mismatch\n", object->getName());
            continue;
@@ -4815,8 +5021,8 @@ IOReturn IOUserClient::externalMethod( uint32_t selector, IOExternalMethodArgume
     if (args->asyncWakePort)
     {
        IOExternalAsyncMethod * method;
-
-       if( !(method = getAsyncTargetAndMethodForIndex(&object, selector)) )
+       object = 0;
+       if( !(method = getAsyncTargetAndMethodForIndex(&object, selector)) || !object )
            return (kIOReturnUnsupported);
 
     if (kIOUCForegroundOnly & method->flags)
@@ -4864,8 +5070,8 @@ IOReturn IOUserClient::externalMethod( uint32_t selector, IOExternalMethodArgume
     else
     {
        IOExternalMethod *      method;
-
-       if( !(method = getTargetAndMethodForIndex(&object, selector)) )
+       object = 0;
+       if( !(method = getTargetAndMethodForIndex(&object, selector)) || !object )
            return (kIOReturnUnsupported);
 
     if (kIOUCForegroundOnly & method->flags)