xnu-2422.1.72.tar.gz
[apple/xnu.git] / iokit / Kernel / IOUserClient.cpp
index 084471c3c7ebd0d479e2dd2d4f24bf9e3e7b1cf6..dcc6e69e2d614cbc9617520da15562a9851d5a79 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 1998-2012 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
 #include <IOKit/IOMemoryDescriptor.h>
 #include <IOKit/IOBufferMemoryDescriptor.h>
 #include <IOKit/IOLib.h>
+#include <IOKit/IOStatisticsPrivate.h>
+#include <IOKit/IOTimeStamp.h>
+#include <IOKit/system.h>
 #include <libkern/OSDebug.h>
 #include <sys/proc.h>
+#include <sys/kauth.h>
+
+#if CONFIG_MACF
+
+extern "C" {
+#include <security/mac_framework.h>
+};
+#include <sys/kauth.h>
+
+#define IOMACF_LOG 0
+
+#endif /* CONFIG_MACF */
 
 #include <IOKit/assert.h>
 
@@ -47,7 +62,7 @@
 
 #define SCALAR64(x) ((io_user_scalar_t)((unsigned int)x))
 #define SCALAR32(x) ((uint32_t )x)
-#define ARG32(x)    ((void *)SCALAR32(x))
+#define ARG32(x)    ((void *)(uintptr_t)SCALAR32(x))
 #define REF64(x)    ((io_user_reference_t)((UInt64)(x)))
 #define REF32(x)    ((int)(x))
 
@@ -57,6 +72,32 @@ enum
     kIOUCAsync64Flag = 1ULL
 };
 
+#if IOKITSTATS
+
+#define IOStatisticsRegisterCounter() \
+do { \
+       reserved->counter = IOStatistics::registerUserClient(this); \
+} while (0)
+
+#define IOStatisticsUnregisterCounter() \
+do { \
+       if (reserved) \
+               IOStatistics::unregisterUserClient(reserved->counter); \
+} while (0)
+
+#define IOStatisticsClientCall() \
+do { \
+       IOStatistics::countUserClientCall(client); \
+} while (0)
+
+#else
+
+#define IOStatisticsRegisterCounter()
+#define IOStatisticsUnregisterCounter()
+#define IOStatisticsClientCall()
+
+#endif /* IOKITSTATS */
+
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
 // definitions we should get from osfmk
@@ -383,9 +424,11 @@ iokit_client_died( io_object_t obj, ipc_port_t /* port */,
 
     if( IKOT_IOKIT_CONNECT == type)
     {
-       if( (client = OSDynamicCast( IOUserClient, obj )))
+       if( (client = OSDynamicCast( IOUserClient, obj ))) {
+               IOStatisticsClientCall();
            client->clientDied();
     }
+    }
     else if( IKOT_IOKIT_OBJECT == type)
     {
        if( (map = OSDynamicCast( IOMemoryMap, obj )))
@@ -538,6 +581,9 @@ bool IOServiceUserNotification::init( mach_port_t port, natural_t type,
                                       void * reference, vm_size_t referenceSize,
                                       bool clientIs64 )
 {
+    if( !super::init())
+        return( false );
+
     newSet = OSArray::withCapacity( 1 );
     if( !newSet)
         return( false );
@@ -563,7 +609,7 @@ bool IOServiceUserNotification::init( mach_port_t port, natural_t type,
     pingMsg->notifyHeader.type = type;
     bcopy( reference, pingMsg->notifyHeader.reference, referenceSize );
 
-    return( super::init() );
+    return( true );
 }
 
 void IOServiceUserNotification::free( void )
@@ -580,8 +626,12 @@ void IOServiceUserNotification::free( void )
 
     super::free();
 
-    if( _pingMsg && _msgSize)
-        IOFree( _pingMsg, _msgSize);
+    if( _pingMsg && _msgSize) {
+               if (_pingMsg->msgHdr.msgh_remote_port) {
+                       iokit_release_port_send(_pingMsg->msgHdr.msgh_remote_port);
+               }
+        IOFree(_pingMsg, _msgSize);
+       }
 
     if( _lastEntry)
         _lastEntry->release();
@@ -625,8 +675,10 @@ bool IOServiceUserNotification::handler( void * ref,
        else
             pingMsg->msgHdr.msgh_local_port = NULL;
 
-        kr = mach_msg_send_from_kernel_proper( &pingMsg->msgHdr,
-                                        pingMsg->msgHdr.msgh_size);
+        kr = mach_msg_send_from_kernel_with_options( &pingMsg->msgHdr,
+                                                    pingMsg->msgHdr.msgh_size,
+                                                    (MACH_SEND_MSG | MACH_SEND_ALWAYS | MACH_SEND_IMPORTANCE),
+                                                    0);
        if( port)
            iokit_release_port( port );
 
@@ -673,6 +725,8 @@ bool IOServiceMessageUserNotification::init( mach_port_t port, natural_t type,
                                void * reference, vm_size_t referenceSize, vm_size_t extraSize,
                                bool client64 )
 {
+    if( !super::init())
+        return( false );
 
     if (referenceSize > sizeof(OSAsyncReference64))
         return( false );
@@ -707,7 +761,7 @@ bool IOServiceMessageUserNotification::init( mach_port_t port, natural_t type,
     pingMsg->notifyHeader.type                 = type;
     bcopy( reference, pingMsg->notifyHeader.reference, referenceSize );
 
-    return( super::init() );
+    return( true );
 }
 
 void IOServiceMessageUserNotification::free( void )
@@ -720,8 +774,12 @@ void IOServiceMessageUserNotification::free( void )
 
     super::free();
 
-    if( _pingMsg && _msgSize)
+    if( _pingMsg && _msgSize) {
+               if (_pingMsg->msgHdr.msgh_remote_port) {
+                       iokit_release_port_send(_pingMsg->msgHdr.msgh_remote_port);
+               }
         IOFree( _pingMsg, _msgSize);
+       }
 }
 
 IOReturn IOServiceMessageUserNotification::_handler( void * target, void * ref,
@@ -744,8 +802,8 @@ IOReturn IOServiceMessageUserNotification::handler( void * ref,
 
     if (kIOMessageCopyClientID == messageType)
     {
-       *((void **) messageArgument) = IOCopyLogNameForPID(owningPID);
-       return (kIOReturnSuccess);
+        *((void **) messageArgument) = OSNumber::withNumber(owningPID, 32);
+        return (kIOReturnSuccess);
     }
 
     data->messageType = messageType;
@@ -776,8 +834,10 @@ IOReturn IOServiceMessageUserNotification::handler( void * ref,
     pingMsg->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_proper( &pingMsg->msgHdr,
-                                   pingMsg->msgHdr.msgh_size);
+    kr = mach_msg_send_from_kernel_with_options( &pingMsg->msgHdr,
+                                                pingMsg->msgHdr.msgh_size,
+                                                (MACH_SEND_MSG | MACH_SEND_ALWAYS | MACH_SEND_IMPORTANCE),
+                                                0);
     if( thisPort)
        iokit_release_port( thisPort );
     if( providerPort)
@@ -827,6 +887,16 @@ void IOUserClient::setAsyncReference64(OSAsyncReference64 asyncRef,
     asyncRef[kIOAsyncCalloutRefconIndex] = refcon;
 }
 
+void IOUserClient::setAsyncReference64(OSAsyncReference64 asyncRef,
+                                       mach_port_t wakePort,
+                                       mach_vm_address_t callback, io_user_reference_t refcon, task_t task)
+{
+    setAsyncReference64(asyncRef, wakePort, callback, refcon);
+    if (vm_map_is_64bit(get_task_map(task))) {
+            asyncRef[kIOAsyncReservedIndex] |= kIOUCAsync64Flag;
+    }
+}
+
 static OSDictionary * CopyConsoleUser(UInt32 uid)
 {
        OSArray * array;
@@ -851,21 +921,27 @@ static OSDictionary * CopyConsoleUser(UInt32 uid)
     return user;
 }
 
-static bool IOUCIsBackgroundTask(task_t task, bool * isBg)
+static OSDictionary * CopyUserOnConsole(void)
 {
-    kern_return_t               kr;
-    task_category_policy_data_t info;
-    mach_msg_type_number_t      count = TASK_CATEGORY_POLICY_COUNT;
-    boolean_t                   get_default = false;
-
-    kr = task_policy_get(current_task(),
-                         TASK_CATEGORY_POLICY,
-                         (task_policy_t) &info,
-                         &count,
-                         &get_default);
-
-    *isBg = ((KERN_SUCCESS == kr) && (info.role == TASK_THROTTLE_APPLICATION));
-    return (kr);
+    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++)
+       {
+           if (kOSBooleanTrue == user->getObject(gIOConsoleSessionOnConsoleKey))
+           {
+               user->retain();
+               break;
+           }
+       }
+       array->release();
+    }
+    return (user);
 }
 
 IOReturn IOUserClient::clientHasPrivilege( void * securityToken,
@@ -882,12 +958,41 @@ IOReturn IOUserClient::clientHasPrivilege( void * securityToken,
     if (!strncmp(privilegeName, kIOClientPrivilegeForeground, 
                 sizeof(kIOClientPrivilegeForeground)))
     {
-        bool isBg;
-        kern_return_t kr = IOUCIsBackgroundTask(current_task(), &isBg);
+       /* is graphics access denied for current task? */
+       if (proc_get_effective_task_policy(current_task(), TASK_POLICY_GPU_DENY) != 0)
+               return (kIOReturnNotPrivileged);
+       else 
+               return (kIOReturnSuccess);
+    }
+
+    if (!strncmp(privilegeName, kIOClientPrivilegeConsoleSession,
+                                sizeof(kIOClientPrivilegeConsoleSession)))
+    {
+       kauth_cred_t cred;
+       proc_t       p;
 
-        if (KERN_SUCCESS != kr)
-            return (kr);
-        return (isBg ? kIOReturnNotPrivileged : kIOReturnSuccess);
+        task = (task_t) securityToken;
+       if (!task)
+           task = current_task();
+       p = (proc_t) get_bsdtask_info(task);
+       kr = kIOReturnNotPrivileged;
+
+       if (p && (cred = kauth_cred_proc_ref(p)))
+       {
+           user = CopyUserOnConsole();
+           if (user)
+           {
+               OSNumber * num;
+               if ((num = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionAuditIDKey)))
+                 && (cred->cr_audit.as_aia_p->ai_asid == (au_asid_t) num->unsigned32BitValue()))
+               {
+                   kr = kIOReturnSuccess;
+               }
+               user->release();
+           }
+           kauth_cred_unref(&cred);
+       }
+       return (kr);
     }
 
     if ((secureConsole = !strncmp(privilegeName, kIOClientPrivilegeSecureConsoleProcess,
@@ -895,7 +1000,7 @@ IOReturn IOUserClient::clientHasPrivilege( void * securityToken,
         task = (task_t)((IOUCProcessToken *)securityToken)->token;
     else
         task = (task_t)securityToken;
-    
+
     count = TASK_SECURITY_TOKEN_COUNT;
     kr = task_info( task, TASK_SECURITY_TOKEN, (task_info_t) &token, &count );
 
@@ -935,28 +1040,28 @@ IOReturn IOUserClient::clientHasPrivilege( void * securityToken,
 
 bool IOUserClient::init()
 {
-    if( getPropertyTable())
-        return true;
-    else
-        return super::init();
+       if (getPropertyTable() || super::init())
+               return reserve();
+       
+       return false;
 }
 
 bool IOUserClient::init(OSDictionary * dictionary)
 {
-    if( getPropertyTable())
-        return true;
-    else
-        return super::init(dictionary);
+       if (getPropertyTable() || super::init(dictionary))
+               return reserve();
+       
+       return false;
 }
 
 bool IOUserClient::initWithTask(task_t owningTask,
                                 void * securityID,
                                 UInt32 type )
-{
-    if( getPropertyTable())
-        return true;
-    else
-        return super::init();
+{      
+       if (getPropertyTable() || super::init())
+               return reserve();
+       
+       return false;
 }
 
 bool IOUserClient::initWithTask(task_t owningTask,
@@ -972,11 +1077,30 @@ bool IOUserClient::initWithTask(task_t owningTask,
     return( ok );
 }
 
+bool IOUserClient::reserve()
+{              
+    if(!reserved) {
+       reserved = IONew(ExpansionData, 1);
+       if (!reserved) {
+           return false;
+       }
+    }
+    setTerminateDefer(NULL, true);
+    IOStatisticsRegisterCounter();
+    
+    return true;
+}
+
 void IOUserClient::free()
 {
     if( mappings)
         mappings->release();
+               
+    IOStatisticsUnregisterCounter();
 
+    if (reserved)
+        IODelete(reserved, ExpansionData, 1);
+               
     super::free();
 }
 
@@ -1070,7 +1194,6 @@ IOReturn IOUserClient::exportObjectToClient(task_t task,
     mach_port_name_t   name;
 
     name = IOMachPort::makeSendRightForTask( task, obj, IKOT_IOKIT_OBJECT );
-    assert( name );
 
     *(mach_port_name_t *)clientObj = name;
     return kIOReturnSuccess;
@@ -1164,8 +1287,20 @@ IOReturn IOUserClient::sendAsyncResult(OSAsyncReference reference,
     return (sendAsyncResult64(reference64, result, args64, numArgs));
 }
 
+IOReturn IOUserClient::sendAsyncResult64WithOptions(OSAsyncReference64 reference,
+                                        IOReturn result, io_user_reference_t args[], UInt32 numArgs, IOOptionBits options)
+{
+       return _sendAsyncResult64(reference, result, args, numArgs, options);
+}
+
 IOReturn IOUserClient::sendAsyncResult64(OSAsyncReference64 reference,
                                         IOReturn result, io_user_reference_t args[], UInt32 numArgs)
+{
+        return _sendAsyncResult64(reference, result, args, numArgs, 0);
+}
+
+IOReturn IOUserClient::_sendAsyncResult64(OSAsyncReference64 reference,
+                                        IOReturn result, io_user_reference_t args[], UInt32 numArgs, IOOptionBits options)
 {
     struct ReplyMsg
     {
@@ -1238,9 +1373,15 @@ IOReturn IOUserClient::sendAsyncResult64(OSAsyncReference64 reference,
            replyMsg.m.msg32.args[idx] = REF32(args[idx]);
     }
 
-     kr = mach_msg_send_from_kernel_proper( &replyMsg.msgHdr,
-            replyMsg.msgHdr.msgh_size);
-    if( KERN_SUCCESS != kr)
+       if ((options & kIOUserNotifyOptionCanDrop) != 0) { 
+               kr = mach_msg_send_from_kernel_with_options( &replyMsg.msgHdr,
+                                                                                replyMsg.msgHdr.msgh_size, MACH_SEND_TIMEOUT, MACH_MSG_TIMEOUT_NONE);
+       } else {
+               /* Fail on full queue. */
+               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 );
     return kr;
 }
@@ -1523,6 +1664,60 @@ kern_return_t is_io_service_get_matching_services_ool(
     return( kr );
 }
 
+
+/* Routine io_service_get_matching_service */
+kern_return_t is_io_service_get_matching_service(
+       mach_port_t master_port,
+       io_string_t matching,
+       io_service_t *service )
+{
+    kern_return_t      kr;
+    OSObject *         obj;
+    OSDictionary *     dict;
+
+    if( master_port != master_device_port)
+        return( kIOReturnNotPrivileged);
+
+    obj = OSUnserializeXML( matching );
+
+    if( (dict = OSDynamicCast( OSDictionary, obj))) {
+        *service = IOService::copyMatchingService( dict );
+       kr = *service ? kIOReturnSuccess : kIOReturnNotFound;
+    } else
+       kr = kIOReturnBadArgument;
+
+    if( obj)
+        obj->release();
+
+    return( kr );
+}
+
+/* Routine io_service_get_matching_services_ool */
+kern_return_t is_io_service_get_matching_service_ool(
+       mach_port_t master_port,
+       io_buf_ptr_t matching,
+       mach_msg_type_number_t matchingCnt,
+       kern_return_t *result,
+       io_object_t *service )
+{
+    kern_return_t      kr;
+    vm_offset_t        data;
+    vm_map_offset_t    map_data;
+
+    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
+       *result = is_io_service_get_matching_service( master_port,
+                       (char *) data, service );
+       vm_deallocate( kernel_map, data, matchingCnt );
+    }
+
+    return( kr );
+}
+
+
 static kern_return_t internal_io_service_add_notification(
        mach_port_t master_port,
        io_name_t notification_type,
@@ -1571,6 +1766,7 @@ 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;
         }
@@ -1732,6 +1928,7 @@ static kern_return_t internal_io_service_add_interest_notification(
                                              reference, referenceSize,
                                             kIOUserNotifyMaxMessageSize,
                                             client64 )) {
+                       iokit_release_port_send(port);
             userNotify->release();
             userNotify = 0;
         }
@@ -1789,7 +1986,7 @@ kern_return_t is_io_service_acknowledge_notification(
 {
     CHECK( IOService, _service, service );
 
-    return( service->acknowledgeNotification( (IONotificationRef) notify_ref,
+    return( service->acknowledgeNotification( (IONotificationRef)(uintptr_t) notify_ref,
                                               (IOOptionBits) response ));
     
 }
@@ -1802,6 +1999,7 @@ kern_return_t is_io_connect_get_notification_semaphore(
 {
     CHECK( IOUserClient, connection, client );
 
+    IOStatisticsClientCall();
     return( client->getNotificationSemaphore( (UInt32) notification_type,
                                               semaphore ));
 }
@@ -1997,7 +2195,7 @@ kern_return_t is_io_registry_entry_get_registry_entry_id(
 // 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( void * data, vm_size_t len,
+static kern_return_t copyoutkdata( const void * data, vm_size_t len,
                                     io_buf_ptr_t * buf )
 {
     kern_return_t      err;
@@ -2202,20 +2400,29 @@ kern_return_t is_io_registry_entry_set_properties
 
     CHECK( IORegistryEntry, registry_entry, entry );
 
+    if( propertiesCnt > sizeof(io_struct_inband_t) * 1024)
+        return( kIOReturnMessageTooLarge);
+
     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) {
 
         // must return success after vm_map_copyout() succeeds
-        obj = OSUnserializeXML( (const char *) data );
+        obj = OSUnserializeXML( (const char *) data, propertiesCnt );
        vm_deallocate( kernel_map, data, propertiesCnt );
 
-        if( obj) {
+       if (!obj)
+           res = kIOReturnBadArgument;
+#if CONFIG_MACF
+       else if (0 != mac_iokit_check_set_properties(kauth_cred_get(),
+           registry_entry, obj))
+           res = kIOReturnNotPermitted;
+#endif
+       else
             res = entry->setProperties( obj );
-            obj->release();
-        } else
-            res = kIOReturnBadArgument;
+       if (obj)
+           obj->release();
     } else
         res = err;
 
@@ -2305,30 +2512,6 @@ kern_return_t is_io_service_request_probe(
     return( service->requestProbe( options ));
 }
 
-
-/* Routine io_service_open */
-kern_return_t is_io_service_open(
-       io_object_t _service,
-       task_t owningTask,
-       uint32_t connect_type,
-       io_object_t *connection )
-{
-    IOUserClient       *       client;
-    IOReturn                   err;
-
-    CHECK( IOService, _service, service );
-
-    err = service->newUserClient( owningTask, (void *) owningTask,
-               connect_type, 0, &client );
-
-    if( err == kIOReturnSuccess) {
-       assert( OSDynamicCast(IOUserClient, client) );
-       *connection = client;
-    }
-
-    return( err);
-}
-
 /* Routine io_service_open_ndr */
 kern_return_t is_io_service_open_extended(
        io_object_t _service,
@@ -2357,13 +2540,16 @@ kern_return_t is_io_service_open_extended(
            vm_offset_t     data;
            vm_map_offset_t map_data;
 
+           if( propertiesCnt > sizeof(io_struct_inband_t))
+               return( kIOReturnMessageTooLarge);
+
            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 );
+               obj = OSUnserializeXML( (const char *) data, propertiesCnt );
                vm_deallocate( kernel_map, data, propertiesCnt );
                propertiesDict = OSDynamicCast(OSDictionary, obj);
                if (!propertiesDict)
@@ -2404,13 +2590,17 @@ kern_return_t is_io_service_open_extended(
            disallowAccess = (crossEndian
                && (kOSBooleanTrue != service->getProperty(kIOUserClientCrossEndianCompatibleKey))
                && (kOSBooleanTrue != client->getProperty(kIOUserClientCrossEndianCompatibleKey)));
-
-           if (disallowAccess)
+            if (disallowAccess) res = kIOReturnUnsupported;
+#if CONFIG_MACF
+           else if (0 != mac_iokit_check_open(kauth_cred_get(), client, connect_type))
+               res = kIOReturnNotPermitted;
+#endif
+           if (kIOReturnSuccess != res)
            {
+               IOStatisticsClientCall();
                client->clientClose();
                client->release();
                client = 0;
-               res = kIOReturnUnsupported;
                break;
            }
            client->sharedInstance = (0 != client->getProperty(kIOUserClientSharedInstanceKey));
@@ -2420,6 +2610,7 @@ kern_return_t is_io_service_open_extended(
                client->setProperty(kIOUserClientCreatorKey, creatorName);
                creatorName->release();
            }
+           client->setTerminateDefer(service, false);
        }
     }
     while (false);
@@ -2440,6 +2631,7 @@ kern_return_t is_io_service_close(
 
     CHECK( IOUserClient, connection, client );
 
+    IOStatisticsClientCall();
     client->clientClose();
 
     return( kIOReturnSuccess );
@@ -2472,6 +2664,7 @@ kern_return_t is_io_connect_set_notification_port(
 {
     CHECK( IOUserClient, connection, client );
 
+    IOStatisticsClientCall();
     return( client->registerNotificationPort( port, notification_type,
                                                (io_user_reference_t) reference ));
 }
@@ -2485,6 +2678,7 @@ kern_return_t is_io_connect_set_notification_port_64(
 {
     CHECK( IOUserClient, connection, client );
 
+    IOStatisticsClientCall();
     return( client->registerNotificationPort( port, notification_type,
                                                reference ));
 }
@@ -2505,6 +2699,7 @@ kern_return_t is_io_connect_map_memory_into_task
 
     CHECK( IOUserClient, connection, client );
 
+    IOStatisticsClientCall();
     map = client->mapClientMemory64( memory_type, into_task, flags, *address );
 
     if( map) {
@@ -2519,7 +2714,6 @@ kern_return_t is_io_connect_map_memory_into_task
            mach_port_name_t name __unused =
                IOMachPort::makeSendRightForTask(
                                     into_task, map, IKOT_IOKIT_OBJECT );
-            assert( name );
 
         } else {
             // keep it with the user client
@@ -2563,6 +2757,8 @@ kern_return_t is_io_connect_map_memory(
     return (err);
 }
 
+} /* extern "C" */
+
 IOMemoryMap * IOUserClient::removeMappingForDescriptor(IOMemoryDescriptor * mem)
 {
     OSIterator *  iter;
@@ -2590,6 +2786,8 @@ IOMemoryMap * IOUserClient::removeMappingForDescriptor(IOMemoryDescriptor * mem)
     return (map);
 }
 
+extern "C" {
+
 /* Routine io_connect_unmap_memory_from_task */
 kern_return_t is_io_connect_unmap_memory_from_task
 (
@@ -2605,6 +2803,7 @@ kern_return_t is_io_connect_unmap_memory_from_task
 
     CHECK( IOUserClient, connection, client );
 
+    IOStatisticsClientCall();
     err = client->clientMemoryForType( (UInt32) memory_type, &options, &memory );
 
     if( memory && (kIOReturnSuccess == err)) {
@@ -2667,6 +2866,7 @@ kern_return_t is_io_connect_add_client(
     CHECK( IOUserClient, connection, client );
     CHECK( IOUserClient, connect_to, to );
 
+    IOStatisticsClientCall();
     return( client->connectClient( to ) );
 }
 
@@ -2681,9 +2881,8 @@ kern_return_t is_io_connect_set_properties(
     return( is_io_registry_entry_set_properties( connection, properties, propertiesCnt, result ));
 }
 
-
 /* Routine io_user_client_method */
-kern_return_t is_io_connect_method
+kern_return_t is_io_connect_method_var_output
 (
        io_connect_t connection,
        uint32_t selector,
@@ -2693,12 +2892,104 @@ kern_return_t is_io_connect_method
        mach_msg_type_number_t inband_inputCnt,
        mach_vm_address_t ool_input,
        mach_vm_size_t ool_input_size,
+       io_struct_inband_t inband_output,
+       mach_msg_type_number_t *inband_outputCnt,
        io_scalar_inband64_t scalar_output,
        mach_msg_type_number_t *scalar_outputCnt,
+       io_buf_ptr_t *var_output,
+       mach_msg_type_number_t *var_outputCnt
+)
+{
+    CHECK( IOUserClient, connection, client );
+
+    IOExternalMethodArguments args;
+    IOReturn ret;
+    IOMemoryDescriptor * inputMD  = 0;
+    OSObject *           structureVariableOutputData = 0;
+
+    bzero(&args.__reserved[0], sizeof(args.__reserved));
+    args.version = kIOExternalMethodArgumentsCurrentVersion;
+
+    args.selector = selector;
+
+    args.asyncWakePort               = MACH_PORT_NULL;
+    args.asyncReference              = 0;
+    args.asyncReferenceCount         = 0;
+    args.structureVariableOutputData = &structureVariableOutputData;
+
+    args.scalarInput = scalar_input;
+    args.scalarInputCount = scalar_inputCnt;
+    args.structureInput = inband_input;
+    args.structureInputSize = inband_inputCnt;
+
+    if (ool_input)
+       inputMD = IOMemoryDescriptor::withAddressRange(ool_input, ool_input_size, 
+                                                   kIODirectionOut, current_task());
+
+    args.structureInputDescriptor = inputMD;
+
+    args.scalarOutput = scalar_output;
+    args.scalarOutputCount = *scalar_outputCnt;
+    args.structureOutput = inband_output;
+    args.structureOutputSize = *inband_outputCnt;
+    args.structureOutputDescriptor = NULL;
+    args.structureOutputDescriptorSize = 0;
+
+    IOStatisticsClientCall();
+    ret = client->externalMethod( selector, &args );
+
+    *scalar_outputCnt = args.scalarOutputCount;
+    *inband_outputCnt = args.structureOutputSize;
+
+    if (var_outputCnt && var_output && (kIOReturnSuccess == ret))
+    {
+       OSSerialize * serialize;
+       OSData      * data;
+       vm_size_t     len;
+
+       if ((serialize = OSDynamicCast(OSSerialize, structureVariableOutputData)))
+       {
+           len = serialize->getLength();
+           *var_outputCnt = len;
+           ret = copyoutkdata(serialize->text(), len, var_output);
+       }
+       else if ((data = OSDynamicCast(OSData, structureVariableOutputData)))
+       {
+           len = data->getLength();
+           *var_outputCnt = len;
+           ret = copyoutkdata(data->getBytesNoCopy(), len, var_output);
+       }
+       else
+       {
+           ret = kIOReturnUnderrun;
+       }
+    }
+
+    if (inputMD)
+       inputMD->release();
+    if (structureVariableOutputData)
+       structureVariableOutputData->release();
+
+    return (ret);
+}
+
+/* Routine io_user_client_method */
+kern_return_t is_io_connect_method
+(
+       io_connect_t connection,
+       uint32_t selector,
+       io_scalar_inband64_t scalar_input,
+       mach_msg_type_number_t scalar_inputCnt,
+       io_struct_inband_t inband_input,
+       mach_msg_type_number_t inband_inputCnt,
+       mach_vm_address_t ool_input,
+       mach_vm_size_t ool_input_size,
        io_struct_inband_t inband_output,
        mach_msg_type_number_t *inband_outputCnt,
+       io_scalar_inband64_t scalar_output,
+       mach_msg_type_number_t *scalar_outputCnt,
        mach_vm_address_t ool_output,
-       mach_vm_size_t * ool_output_size
+       mach_vm_size_t *ool_output_size
 )
 {
     CHECK( IOUserClient, connection, client );
@@ -2713,9 +3004,10 @@ kern_return_t is_io_connect_method
 
     args.selector = selector;
 
-    args.asyncWakePort       = MACH_PORT_NULL;
-    args.asyncReference      = 0;
-    args.asyncReferenceCount = 0;
+    args.asyncWakePort               = MACH_PORT_NULL;
+    args.asyncReference              = 0;
+    args.asyncReferenceCount         = 0;
+    args.structureVariableOutputData = 0;
 
     args.scalarInput = scalar_input;
     args.scalarInputCount = scalar_inputCnt;
@@ -2733,15 +3025,16 @@ kern_return_t is_io_connect_method
     args.structureOutput = inband_output;
     args.structureOutputSize = *inband_outputCnt;
 
-    if (ool_output)
+    if (ool_output && ool_output_size)
     {
        outputMD = IOMemoryDescriptor::withAddressRange(ool_output, *ool_output_size, 
                                                    kIODirectionIn, current_task());
     }
 
     args.structureOutputDescriptor = outputMD;
-    args.structureOutputDescriptorSize = *ool_output_size;
+    args.structureOutputDescriptorSize = ool_output_size ? *ool_output_size : 0;
 
+    IOStatisticsClientCall();
     ret = client->externalMethod( selector, &args );
 
     *scalar_outputCnt = args.scalarOutputCount;
@@ -2770,10 +3063,10 @@ kern_return_t is_io_connect_async_method
        mach_msg_type_number_t inband_inputCnt,
        mach_vm_address_t ool_input,
        mach_vm_size_t ool_input_size,
-       io_scalar_inband64_t scalar_output,
-       mach_msg_type_number_t *scalar_outputCnt,
        io_struct_inband_t inband_output,
        mach_msg_type_number_t *inband_outputCnt,
+       io_scalar_inband64_t scalar_output,
+       mach_msg_type_number_t *scalar_outputCnt,
        mach_vm_address_t ool_output,
        mach_vm_size_t * ool_output_size
 )
@@ -2823,6 +3116,7 @@ kern_return_t is_io_connect_async_method
     args.structureOutputDescriptor = outputMD;
     args.structureOutputDescriptorSize = *ool_output_size;
 
+    IOStatisticsClientCall();
     ret = client->externalMethod( selector, &args );
 
     *inband_outputCnt = args.structureOutputSize;
@@ -2860,8 +3154,8 @@ kern_return_t is_io_connect_method_scalarI_scalarO(
                    _input, inputCount, 
                    NULL, 0,
                    0, 0,
-                   _output, outputCount,
                    NULL, &struct_outputCnt,
+                   _output, outputCount,
                    0, &ool_output_size);
 
     for (i = 0; i < *outputCount; i++)
@@ -2979,8 +3273,8 @@ kern_return_t is_io_async_method_scalarI_scalarO(
                    _input, inputCount, 
                    NULL, 0,
                    0, 0,
-                   _output, outputCount,
                    NULL, &struct_outputCnt,
+                   _output, outputCount,
                    0, &ool_output_size);
 
     for (i = 0; i < *outputCount; i++)
@@ -3019,8 +3313,8 @@ kern_return_t is_io_async_method_scalarI_structureO(
                    _input, inputCount, 
                    NULL, 0,
                    0, 0,
-                   NULL, &scalar_outputCnt,
                    output, outputCount,
+                   NULL, &scalar_outputCnt,
                    0, &ool_output_size));
 }
 
@@ -3056,8 +3350,8 @@ kern_return_t is_io_async_method_scalarI_structureI(
                    _input, inputCount, 
                    inputStruct, inputStructCount,
                    0, 0,
-                   NULL, &scalar_outputCnt,
                    NULL, &inband_outputCnt,
+                   NULL, &scalar_outputCnt,
                    0, &ool_output_size));
 }
 
@@ -3087,8 +3381,8 @@ kern_return_t is_io_async_method_structureI_structureO(
                    NULL, 0, 
                    input, inputCount,
                    0, 0,
-                   NULL, &scalar_outputCnt,
                    output, outputCount,
+                   NULL, &scalar_outputCnt,
                    0, &ool_output_size));
 }
 
@@ -3207,8 +3501,8 @@ kern_return_t is_io_connect_method_scalarI_structureO(
                    _input, inputCount, 
                    NULL, 0,
                    0, 0,
-                   NULL, &scalar_outputCnt,
                    output, outputCount,
+                   NULL, &scalar_outputCnt,
                    0, &ool_output_size));
 }
 
@@ -3380,8 +3674,8 @@ kern_return_t is_io_connect_method_scalarI_structureI(
                    _input, inputCount, 
                    inputStruct, inputStructCount,
                    0, 0,
-                   NULL, &scalar_outputCnt,
                    NULL, &inband_outputCnt,
+                   NULL, &scalar_outputCnt,
                    0, &ool_output_size));
 }
 
@@ -3423,25 +3717,25 @@ kern_return_t shim_io_connect_method_scalarI_structureI(
            case 4:
                err = (object->*func)( ARG32(input[0]), ARG32(input[1]), (void *)  input[2],
                                        ARG32(input[3]),
-                                       inputStruct, (void *)inputStructCount );
+                                       inputStruct, (void *)(uintptr_t)inputStructCount );
                break;
            case 3:
                err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
-                                       inputStruct, (void *)inputStructCount,
+                                       inputStruct, (void *)(uintptr_t)inputStructCount,
                                        0 );
                break;
            case 2:
                err = (object->*func)( ARG32(input[0]), ARG32(input[1]),
-                                       inputStruct, (void *)inputStructCount,
+                                       inputStruct, (void *)(uintptr_t)inputStructCount,
                                        0, 0 );
                break;
            case 1:
                err = (object->*func)( ARG32(input[0]),
-                                       inputStruct, (void *)inputStructCount,
+                                       inputStruct, (void *)(uintptr_t)inputStructCount,
                                        0, 0, 0 );
                break;
            case 0:
-               err = (object->*func)( inputStruct, (void *)inputStructCount,
+               err = (object->*func)( inputStruct, (void *)(uintptr_t)inputStructCount,
                                        0, 0, 0, 0 );
                break;
 
@@ -3502,29 +3796,29 @@ kern_return_t shim_io_async_method_scalarI_structureI(
                 err = (object->*func)( reference,
                                         ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
                                         ARG32(input[3]),
-                                        inputStruct, (void *)inputStructCount );
+                                        inputStruct, (void *)(uintptr_t)inputStructCount );
                 break;
             case 3:
                 err = (object->*func)( reference,
                                         ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
-                                        inputStruct, (void *)inputStructCount,
+                                        inputStruct, (void *)(uintptr_t)inputStructCount,
                                         0 );
                 break;
             case 2:
                 err = (object->*func)( reference,
                                         ARG32(input[0]), ARG32(input[1]),
-                                        inputStruct, (void *)inputStructCount,
+                                        inputStruct, (void *)(uintptr_t)inputStructCount,
                                         0, 0 );
                 break;
             case 1:
                 err = (object->*func)( reference,
                                         ARG32(input[0]),
-                                        inputStruct, (void *)inputStructCount,
+                                        inputStruct, (void *)(uintptr_t)inputStructCount,
                                         0, 0, 0 );
                 break;
             case 0:
                 err = (object->*func)( reference,
-                                        inputStruct, (void *)inputStructCount,
+                                        inputStruct, (void *)(uintptr_t)inputStructCount,
                                         0, 0, 0, 0 );
                 break;
 
@@ -3553,8 +3847,8 @@ kern_return_t is_io_connect_method_structureI_structureO(
                    NULL, 0, 
                    input, inputCount,
                    0, 0,
-                   NULL, &scalar_outputCnt,
                    output, outputCount,
+                   NULL, &scalar_outputCnt,
                    0, &ool_output_size));
 }
 
@@ -3589,12 +3883,12 @@ kern_return_t shim_io_connect_method_structureI_structureO(
        if( method->count1) {
            if( method->count0) {
                err = (object->*func)( input, output,
-                                       (void *)inputCount, outputCount, 0, 0 );
+                                       (void *)(uintptr_t)inputCount, outputCount, 0, 0 );
            } else {
                err = (object->*func)( output, outputCount, 0, 0, 0, 0 );
            }
        } else {
-               err = (object->*func)( input, (void *)inputCount, 0, 0, 0, 0 );
+               err = (object->*func)( input, (void *)(uintptr_t)inputCount, 0, 0, 0, 0 );
        }
     }
     while( false);
@@ -3644,84 +3938,18 @@ kern_return_t shim_io_async_method_structureI_structureO(
             if( method->count0) {
                 err = (object->*func)( reference,
                                        input, output,
-                                        (void *)inputCount, outputCount, 0, 0 );
+                                        (void *)(uintptr_t)inputCount, outputCount, 0, 0 );
             } else {
                 err = (object->*func)( reference,
                                        output, outputCount, 0, 0, 0, 0 );
             }
         } else {
                 err = (object->*func)( reference,
-                                       input, (void *)inputCount, 0, 0, 0, 0 );
-        }
-    }
-    while( false);
-
-    return( err);
-}
-
-/* Routine io_make_matching */
-kern_return_t is_io_make_matching(
-       mach_port_t         master_port,
-       uint32_t            type,
-       uint32_t                options,
-        io_struct_inband_t     input,
-        mach_msg_type_number_t inputCount,
-       io_string_t     matching )
-{
-    OSSerialize *      s;
-    IOReturn           err = kIOReturnSuccess;
-    OSDictionary *     dict;
-
-    if( master_port != master_device_port)
-        return( kIOReturnNotPrivileged);
-
-    switch( type) {
-
-       case kIOServiceMatching:
-            dict = IOService::serviceMatching( gIOServiceKey );
-           break;
-
-       case kIOBSDNameMatching:
-           dict = IOBSDNameMatching( (const char *) input );
-           break;
-
-       case kIOOFPathMatching:
-           dict = IOOFPathMatching( (const char *) input,
-                                    matching, sizeof( io_string_t));
-           break;
-
-       default:
-           dict = 0;
-    }
-
-    if( !dict)
-       return( kIOReturnUnsupported);
-
-    do {
-        s = OSSerialize::withCapacity(4096);
-        if( !s) {
-            err = kIOReturnNoMemory;
-           continue;
-       }
-        s->clearText();
-        if( !dict->serialize( s )) {
-            err = kIOReturnUnsupported;
-           continue;
+                                       input, (void *)(uintptr_t)inputCount, 0, 0, 0, 0 );
         }
-
-        if( s->getLength() > sizeof( io_string_t)) {
-            err = kIOReturnNoMemory;
-           continue;
-        } else
-            strlcpy(matching, s->text(), sizeof(io_string_t));
     }
     while( false);
 
-    if( s)
-       s->release();
-    if( dict)
-       dict->release();
-
     return( err);
 }
 
@@ -3753,6 +3981,9 @@ kern_return_t is_io_catalog_send_data(
     if (inData) {
         vm_map_offset_t map_data;
 
+        if( inDataCount > sizeof(io_struct_inband_t) * 1024)
+            return( kIOReturnMessageTooLarge);
+
         kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t)inData);
                data = CAST_DOWN(vm_offset_t, map_data);
 
@@ -3762,7 +3993,7 @@ kern_return_t is_io_catalog_send_data(
         // must return success after vm_map_copyout() succeeds
 
         if( inDataCount ) {
-            obj = (OSObject *)OSUnserializeXML((const char *)data);
+            obj = (OSObject *)OSUnserializeXML((const char *)data, inDataCount);
             vm_deallocate( kernel_map, data, inDataCount );
             if( !obj) {
                 *result = kIOReturnNoMemory;
@@ -3772,6 +4003,23 @@ kern_return_t is_io_catalog_send_data(
     }
 
     switch ( flag ) {
+        case kIOCatalogResetDrivers:
+        case kIOCatalogResetDriversNoMatch: {
+                OSArray * array;
+
+                array = OSDynamicCast(OSArray, obj);
+                if (array) {
+                   if ( !gIOCatalogue->resetAndAddDrivers(array,
+                        flag == kIOCatalogResetDrivers) ) {
+
+                        kr = kIOReturnError;
+                    }
+                } else {
+                    kr = kIOReturnBadArgument;
+                }
+            }
+            break;
+
         case kIOCatalogAddDrivers: 
         case kIOCatalogAddDriversNoMatch: {
                 OSArray * array;
@@ -3827,6 +4075,7 @@ kern_return_t is_io_catalog_send_data(
 
         case kIOCatalogKextdActive:
 #if !NO_KEXTD
+            IOServiceTrace(IOSERVICE_KEXTD_ALIVE, 0, 0, 0, 0);
             OSKext::setKextdActive();
 
            /* Dump all nonloaded startup extensions; kextd will now send them
@@ -3844,6 +4093,7 @@ kern_return_t is_io_catalog_send_data(
                 if (!clearedBusy) {
                     IOService * serviceRoot = IOService::getServiceRoot();
                     if (serviceRoot) {
+                        IOServiceTrace(IOSERVICE_KEXTD_READY, 0, 0, 0, 0);
                         serviceRoot->adjustBusy(-1);
                         clearedBusy = true;
                     }
@@ -3881,6 +4131,7 @@ kern_return_t is_io_catalog_terminate(
         return( kr );
 
     switch ( flag ) {
+#if !defined(SECURE_KERNEL)
         case kIOCatalogServiceTerminate:
             OSIterator *       iter;
             IOService *                service;
@@ -3910,6 +4161,7 @@ kern_return_t is_io_catalog_terminate(
             kr = gIOCatalogue->terminateDriversForModule(name,
                                         flag == kIOCatalogModuleUnload);
             break;
+#endif
 
         default:
             kr = kIOReturnBadArgument;
@@ -4048,6 +4300,8 @@ kern_return_t iokit_user_client_trap(struct iokit_user_client_trap_args *args)
     return result;
 }
 
+} /* extern "C" */
+
 IOReturn IOUserClient::externalMethod( uint32_t selector, IOExternalMethodArguments * args,
                                        IOExternalMethodDispatch * dispatch, OSObject * target, void * reference )
 {
@@ -4113,10 +4367,8 @@ IOReturn IOUserClient::externalMethod( uint32_t selector, IOExternalMethodArgume
 
     if (kIOUCForegroundOnly & method->flags)
     {
-        bool isBg;
-        kern_return_t kr = IOUCIsBackgroundTask(current_task(), &isBg);
-    
-        if ((KERN_SUCCESS == kr) && isBg)
+       /* is graphics access denied for current task? */
+       if (proc_get_effective_task_policy(current_task(), TASK_POLICY_GPU_DENY) != 0)
             return (kIOReturnNotPermitted);
     }
 
@@ -4165,11 +4417,10 @@ IOReturn IOUserClient::externalMethod( uint32_t selector, IOExternalMethodArgume
 
     if (kIOUCForegroundOnly & method->flags)
     {
-        bool isBg;
-        kern_return_t kr = IOUCIsBackgroundTask(current_task(), &isBg);
-    
-        if ((KERN_SUCCESS == kr) && isBg)
+       /* is graphics access denied for current task? */
+       if (proc_get_effective_task_policy(current_task(), TASK_POLICY_GPU_DENY) != 0)
             return (kIOReturnNotPermitted);
+    
     }
 
        switch (method->flags & kIOUCTypeMask)
@@ -4211,8 +4462,6 @@ IOReturn IOUserClient::externalMethod( uint32_t selector, IOExternalMethodArgume
 }
 
 
-};     /* extern "C" */
-
 #if __LP64__
 OSMetaClassDefineReservedUnused(IOUserClient, 0);
 OSMetaClassDefineReservedUnused(IOUserClient, 1);