]> git.saurik.com Git - apple/xnu.git/blobdiff - iokit/Kernel/IOUserClient.cpp
xnu-792.25.20.tar.gz
[apple/xnu.git] / iokit / Kernel / IOUserClient.cpp
index 9a05dc3bb0a1eff8b4c3124525a49cf5787ab9d9..d68a7363203b0e97aa1c39ad22e1b24239ba50c4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1998-2004 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -22,9 +22,9 @@
 
 
 #include <IOKit/IOKitServer.h>
+#include <IOKit/IOKitKeysPrivate.h>
 #include <IOKit/IOUserClient.h>
 #include <IOKit/IOService.h>
-#include <IOKit/IOService.h>
 #include <IOKit/IORegistryEntry.h>
 #include <IOKit/IOCatalogue.h>
 #include <IOKit/IOMemoryDescriptor.h>
@@ -55,6 +55,8 @@ 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);
@@ -66,6 +68,7 @@ extern void iokit_release_port( 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" */
@@ -383,7 +386,7 @@ class IOServiceUserNotification : public IOUserNotification
         OSNotificationHeader           notifyHeader;
     };
 
-    enum { kMaxOutstanding = 256 };
+    enum { kMaxOutstanding = 1024 };
 
     PingMsg *          pingMsg;
     vm_size_t          msgSize;
@@ -754,52 +757,95 @@ void IOUserClient::setAsyncReference(OSAsyncReference asyncRef,
     asyncRef[kIOAsyncCalloutRefconIndex] = (natural_t) refcon;
 }
 
-IOReturn IOUserClient::clientHasPrivilege( void * securityToken,
-                                            const char * privilegeName )
+inline OSDictionary * CopyConsoleUser(UInt32 uid)
 {
-    kern_return_t         kr;
-    security_token_t      token;
-    mach_msg_type_number_t count;
-
-    count = TASK_SECURITY_TOKEN_COUNT;
-    kr = task_info( (task_t) securityToken, TASK_SECURITY_TOKEN,
-                   (task_info_t) &token, &count );
-
-    if (KERN_SUCCESS != kr)
-    {}
-    else if (!strcmp(privilegeName, kIOClientPrivilegeAdministrator))
-    {
-       if (0 != token.val[0])
-           kr = kIOReturnNotPrivileged;
-    }
-    else if (!strcmp(privilegeName, kIOClientPrivilegeLocalUser))
-    {
-       OSArray *      array;
-       OSDictionary * user = 0;
+       OSArray * array;
+       OSDictionary * user = 0; 
 
        if ((array = OSDynamicCast(OSArray,
            IORegistryEntry::getRegistryRoot()->copyProperty(gIOConsoleUsersKey))))
        {
            for (unsigned int idx = 0;
                    (user = OSDynamicCast(OSDictionary, array->getObject(idx)));
-                   idx++)
-           {
-               OSNumber * num;
-               if ((num = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionUIDKey)))
-                 && (token.val[0] == num->unsigned32BitValue()))
-                   break;
+                   idx++) {
+            OSNumber * num;
+            
+            if ((num = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionUIDKey)))
+              && (uid == num->unsigned32BitValue())) {
+                user->retain();
+                break;
+            }
            }
            array->release();
        }
-       if (!user)
-           kr = kIOReturnNotPrivileged;
-    }
+    return user;
+}
+
+IOReturn IOUserClient::clientHasPrivilege( void * securityToken,
+                                            const char * privilegeName )
+{
+    kern_return_t           kr;
+    security_token_t        token;
+    mach_msg_type_number_t  count;
+    task_t                  task;
+    OSDictionary *          user;
+    bool                    secureConsole;
+
+    if ((secureConsole = !strcmp(privilegeName, kIOClientPrivilegeSecureConsoleProcess)))
+        task = (task_t)((IOUCProcessToken *)securityToken)->token;
     else
-       kr = kIOReturnUnsupported;
+        task = (task_t)securityToken;
+    
+    count = TASK_SECURITY_TOKEN_COUNT;
+    kr = task_info( task, TASK_SECURITY_TOKEN, (task_info_t) &token, &count );
+
+    if (KERN_SUCCESS != kr)
+    {}
+    else if (!strcmp(privilegeName, kIOClientPrivilegeAdministrator)) {
+        if (0 != token.val[0])
+            kr = kIOReturnNotPrivileged;
+    } else if (!strcmp(privilegeName, kIOClientPrivilegeLocalUser)) {
+        user = CopyConsoleUser(token.val[0]);
+        if ( user )
+            user->release();
+        else
+            kr = kIOReturnNotPrivileged;            
+    } else if (secureConsole || !strcmp(privilegeName, kIOClientPrivilegeConsoleUser)) {
+        user = CopyConsoleUser(token.val[0]);
+        if ( user ) {
+            if (user->getObject(gIOConsoleSessionOnConsoleKey) != kOSBooleanTrue)
+                kr = kIOReturnNotPrivileged;
+            else if ( secureConsole ) {
+                OSNumber * pid = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionSecureInputPIDKey));
+                if ( pid && pid->unsigned32BitValue() != ((IOUCProcessToken *)securityToken)->pid)
+                    kr = kIOReturnNotPrivileged;
+            }
+            user->release();
+        }
+        else 
+            kr = kIOReturnNotPrivileged;
+    } else
+        kr = kIOReturnUnsupported;
 
     return (kr);
 }
 
+bool IOUserClient::init()
+{
+    if( getPropertyTable())
+        return true;
+    else
+        return super::init();
+}
+
+bool IOUserClient::init(OSDictionary * dictionary)
+{
+    if( getPropertyTable())
+        return true;
+    else
+        return super::init(dictionary);
+}
+
 bool IOUserClient::initWithTask(task_t owningTask,
                                 void * securityID,
                                 UInt32 type )
@@ -1015,13 +1061,100 @@ kern_return_t is_io_object_get_class(
        io_object_t object,
        io_name_t className )
 {
+       const OSMetaClass* my_obj = NULL;
+
     if( !object)
         return( kIOReturnBadArgument );
-
-    strcpy( className, object->getMetaClass()->getClassName());
+               
+       my_obj = object->getMetaClass();
+       if (!my_obj) {
+               return (kIOReturnNotFound);
+       }
+       
+    strcpy( className, my_obj->getClassName());
     return( kIOReturnSuccess );
 }
 
+/* Routine io_object_get_superclass */
+kern_return_t is_io_object_get_superclass(
+       mach_port_t master_port,
+       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;
+
+       if (!obj_name || !class_name) 
+               return (kIOReturnBadArgument);
+
+    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();
+       }
+       if (my_obj) {
+               superclass = my_obj->getSuperClass();
+       }
+       
+       if (!superclass)  {
+               return( kIOReturnNotFound );
+       }
+
+       my_cstr = superclass->getClassName();
+               
+       if (my_cstr) {
+               strncpy(class_name, my_cstr, sizeof(io_name_t)-1);
+               return( kIOReturnSuccess );
+       }
+       return (kIOReturnNotFound);
+}
+
+/* Routine io_object_get_bundle_identifier */
+kern_return_t is_io_object_get_bundle_identifier(
+       mach_port_t master_port,
+       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;
+
+       if (!obj_name || !bundle_name) 
+               return (kIOReturnBadArgument);
+
+    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();
+       }
+
+       if (my_obj) {
+               identifier = my_obj->getKmodName();
+       }
+       if (!identifier) {
+               return( kIOReturnNotFound );
+       }
+       
+       my_cstr = identifier->getCStringNoCopy();
+       if (my_cstr) {
+               strncpy(bundle_name, identifier->getCStringNoCopy(), sizeof(io_name_t)-1);
+               return( kIOReturnSuccess );
+       }
+
+       return (kIOReturnBadArgument);
+}
+
 /* Routine io_object_conforms_to */
 kern_return_t is_io_object_conforms_to(
        io_object_t object,
@@ -1124,8 +1257,10 @@ kern_return_t is_io_service_match_property_table_ool(
 {
     kern_return_t      kr;
     vm_offset_t        data;
+    vm_map_offset_t    map_data;
 
-    kr = vm_map_copyout( kernel_map, &data, (vm_map_copy_t) matching );
+    kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) matching );
+    data = CAST_DOWN(vm_offset_t, map_data);
 
     if( KERN_SUCCESS == kr) {
         // must return success after vm_map_copyout() succeeds
@@ -1174,8 +1309,10 @@ kern_return_t is_io_service_get_matching_services_ool(
 {
     kern_return_t      kr;
     vm_offset_t        data;
+    vm_map_offset_t    map_data;
 
-    kr = vm_map_copyout( kernel_map, &data, (vm_map_copy_t) matching );
+    kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) matching );
+    data = CAST_DOWN(vm_offset_t, map_data);
 
     if( KERN_SUCCESS == kr) {
         // must return success after vm_map_copyout() succeeds
@@ -1275,8 +1412,10 @@ kern_return_t is_io_service_add_notification_ool(
 {
     kern_return_t      kr;
     vm_offset_t        data;
+    vm_map_offset_t    map_data;
 
-    kr = vm_map_copyout( kernel_map, &data, (vm_map_copy_t) matching );
+    kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) matching );
+    data = CAST_DOWN(vm_offset_t, map_data);
 
     if( KERN_SUCCESS == kr) {
         // must return success after vm_map_copyout() succeeds
@@ -1558,7 +1697,7 @@ static kern_return_t copyoutkdata( void * data, vm_size_t len,
     kern_return_t      err;
     vm_map_copy_t      copy;
 
-    err = vm_map_copyin( kernel_map, (vm_offset_t) data, len,
+    err = vm_map_copyin( kernel_map, CAST_USER_ADDR_T(data), len,
                     false /* src_destroy */, &copy);
 
     assert( err == KERN_SUCCESS );
@@ -1630,6 +1769,7 @@ kern_return_t is_io_registry_entry_get_property_bytes(
     return( ret );
 }
 
+
 /* Routine io_registry_entry_get_property */
 kern_return_t is_io_registry_entry_get_property(
        io_object_t registry_entry,
@@ -1752,10 +1892,12 @@ kern_return_t is_io_registry_entry_set_properties
     kern_return_t      err;
     IOReturn           res;
     vm_offset_t        data;
+    vm_map_offset_t    map_data;
 
     CHECK( IORegistryEntry, registry_entry, entry );
 
-    err = vm_map_copyout( kernel_map, &data, (vm_map_copy_t) properties );
+    err = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) properties );
+    data = CAST_DOWN(vm_offset_t, map_data);
 
     if( KERN_SUCCESS == err) {
 
@@ -1861,7 +2003,7 @@ kern_return_t is_io_service_open(
     CHECK( IOService, _service, service );
 
     err = service->newUserClient( owningTask, (void *) owningTask,
-               connect_type, &client );
+               connect_type, 0, &client );
 
     if( err == kIOReturnSuccess) {
        assert( OSDynamicCast(IOUserClient, client) );
@@ -1871,6 +2013,101 @@ kern_return_t is_io_service_open(
     return( err);
 }
 
+/* Routine io_service_open_ndr */
+kern_return_t is_io_service_open_extended(
+       io_object_t _service,
+       task_t owningTask,
+       int connect_type,
+       NDR_record_t ndr,
+       io_buf_ptr_t properties,
+       mach_msg_type_number_t propertiesCnt,
+        natural_t * result,
+       io_object_t *connection )
+{
+    IOUserClient * client = 0;
+    kern_return_t  err = KERN_SUCCESS;
+    IOReturn      res = kIOReturnSuccess;
+    OSDictionary * propertiesDict = 0;
+    bool          crossEndian;
+    bool          disallowAccess;
+
+    CHECK( IOService, _service, service );
+
+    do
+    {
+       if (properties)
+       {
+           OSObject *      obj;
+           vm_offset_t     data;
+           vm_map_offset_t map_data;
+
+           err = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) properties );
+           res = err;
+           data = CAST_DOWN(vm_offset_t, map_data);
+           if (KERN_SUCCESS == err)
+           {
+               // must return success after vm_map_copyout() succeeds
+               obj = OSUnserializeXML( (const char *) data );
+               vm_deallocate( kernel_map, data, propertiesCnt );
+               propertiesDict = OSDynamicCast(OSDictionary, obj);
+               if (!propertiesDict)
+               {
+                   res = kIOReturnBadArgument;
+                   if (obj)
+                       obj->release();
+               }
+           }
+           if (kIOReturnSuccess != res)
+               break;
+       }
+
+       crossEndian = (ndr.int_rep != NDR_record.int_rep);
+       if (crossEndian)
+       {
+           if (!propertiesDict)
+               propertiesDict = OSDictionary::withCapacity(4);
+           OSData * data = OSData::withBytes(&ndr, sizeof(ndr));
+           if (data)
+           {
+               if (propertiesDict)
+                   propertiesDict->setObject(kIOUserClientCrossEndianKey, data);
+               data->release();
+           }
+       }
+
+       res = service->newUserClient( owningTask, (void *) owningTask,
+                   connect_type, propertiesDict, &client );
+
+       if (propertiesDict)
+           propertiesDict->release();
+
+       if (res == kIOReturnSuccess)
+       {
+           assert( OSDynamicCast(IOUserClient, client) );
+
+           disallowAccess = (crossEndian
+               && (kOSBooleanTrue != service->getProperty(kIOUserClientCrossEndianCompatibleKey))
+               && (kOSBooleanTrue != client->getProperty(kIOUserClientCrossEndianCompatibleKey)));
+
+           if (disallowAccess)
+           {
+               client->clientClose();
+               client->release();
+               client = 0;
+               res = kIOReturnUnsupported;
+               break;
+           }
+           client->sharedInstance = (0 != client->getProperty(kIOUserClientSharedInstanceKey));
+       }
+    }
+    while (false);
+
+    *connection = client;
+    *result = res;
+
+    return (err);
+}
+
 /* Routine io_service_close */
 kern_return_t is_io_service_close(
        io_object_t connection )
@@ -1937,7 +2174,8 @@ kern_return_t is_io_connect_map_memory(
         if( mapSize)
             *mapSize = map->getLength();
 
-        if( task != current_task()) {
+        if( client->sharedInstance
+           || (task != current_task())) {
             // push a name out to the task owning the map,
             // so we can clean up maps
 #if IOASSERT
@@ -1965,6 +2203,33 @@ kern_return_t is_io_connect_map_memory(
     return( err );
 }
 
+IOMemoryMap * IOUserClient::removeMappingForDescriptor(IOMemoryDescriptor * mem)
+{
+    OSIterator *  iter;
+    IOMemoryMap * map = 0;
+
+    IOLockLock(gIOObjectPortLock);
+
+    iter = OSCollectionIterator::withCollection(mappings);
+    if(iter)
+    {
+        while ((map = OSDynamicCast(IOMemoryMap, iter->getNextObject())))
+        {
+            if(mem == map->getMemoryDescriptor())
+            {
+                map->retain();
+                mappings->removeObject(map);
+                break;
+            }
+        }
+        iter->release();
+    }
+
+    IOLockUnlock(gIOObjectPortLock);
+
+    return (map);
+}
+
 kern_return_t is_io_connect_unmap_memory(
        io_object_t     connect,
        int             type,
@@ -1987,14 +2252,28 @@ kern_return_t is_io_connect_unmap_memory(
 
        map = memory->map( task, mapAddr, options );
        memory->release();
-        if( map) {
+        if( map)
+       {
             IOLockLock( gIOObjectPortLock);
             if( client->mappings)
                 client->mappings->removeObject( map);
             IOLockUnlock( gIOObjectPortLock);
-            IOMachPort::releasePortForObject( map, IKOT_IOKIT_OBJECT );
-            map->release();
-        } else
+
+           mach_port_name_t name = 0;
+           if (task != current_task())
+               name = IOMachPort::makeSendRightForTask( task, map, IKOT_IOKIT_OBJECT );
+           if (name)
+           {
+               map->unmap();
+               err = iokit_mod_send_right( task, name, -2 );
+               err = kIOReturnSuccess;
+           }
+           else
+               IOMachPort::releasePortForObject( map, IKOT_IOKIT_OBJECT );
+           if (task == current_task())
+               map->release();
+        }
+       else
             err = kIOReturnBadArgument;
     }
 
@@ -2671,8 +2950,12 @@ kern_return_t is_io_catalog_send_data(
     if(flag != kIOCatalogRemoveKernelLinker && ( !inData || !inDataCount) )
         return kIOReturnBadArgument;
 
-    if (data) {
-        kr = vm_map_copyout( kernel_map, &data, (vm_map_copy_t)inData);
+    if (inData) {
+        vm_map_offset_t map_data;
+
+        kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t)inData);
+       data = CAST_DOWN(vm_offset_t, map_data);
+
         if( kr != KERN_SUCCESS)
             return kr;
 
@@ -2842,10 +3125,11 @@ kern_return_t is_io_catalog_get_data(
         vm_size_t size;
 
         size = s->getLength();
-        kr = vm_allocate(kernel_map, &data, size, true);
+        kr = vm_allocate(kernel_map, &data, size, VM_FLAGS_ANYWHERE);
         if ( kr == kIOReturnSuccess ) {
             bcopy(s->text(), (void *)data, size);
-            kr = vm_map_copyin(kernel_map, data, size, true, &copy);
+            kr = vm_map_copyin(kernel_map, (vm_map_address_t)data,
+                              (vm_map_size_t)size, true, &copy);
             *outData = (char *)copy;
             *outDataCount = size;
         }
@@ -2911,19 +3195,17 @@ kern_return_t is_io_catalog_reset(
     return kIOReturnSuccess;
 }
 
-kern_return_t iokit_user_client_trap(io_object_t userClientRef, UInt32 index,
-                                    void *p1, void *p2, void *p3,
-                                    void *p4, void *p5, void *p6)
+kern_return_t iokit_user_client_trap(struct iokit_user_client_trap_args *args)
 {
     kern_return_t result = kIOReturnBadArgument;
     IOUserClient *userClient;
 
     if ((userClient = OSDynamicCast(IOUserClient,
-            iokit_lookup_connect_ref_current_task(userClientRef)))) {
+            iokit_lookup_connect_ref_current_task((OSObject *)(args->userClientRef))))) {
         IOExternalTrap *trap;
         IOService *target = NULL;
 
-        trap = userClient->getTargetAndTrapForIndex(&target, index);
+        trap = userClient->getTargetAndTrapForIndex(&target, args->index);
 
         if (trap && target) {
             IOTrap func;
@@ -2931,7 +3213,7 @@ kern_return_t iokit_user_client_trap(io_object_t userClientRef, UInt32 index,
             func = trap->func;
 
             if (func) {
-                result = (target->*func)(p1, p2, p3, p4, p5, p6);
+                result = (target->*func)(args->p1, args->p2, args->p3, args->p4, args->p5, args->p6);
             }
         }