]> git.saurik.com Git - apple/xnu.git/blobdiff - iokit/Kernel/IOUserClient.cpp
xnu-7195.81.3.tar.gz
[apple/xnu.git] / iokit / Kernel / IOUserClient.cpp
index 12ae32416702a74a2c35c1e9403f20c5a111ba18..12bc47e4656212a1c29f03477d1587c145d3ceb1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998-2014 Apple Inc. All rights reserved.
+ * Copyright (c) 1998-2019 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
@@ -28,6 +28,7 @@
 
 
 #include <libkern/c++/OSKext.h>
+#include <libkern/c++/OSSharedPtr.h>
 #include <IOKit/IOKitServer.h>
 #include <IOKit/IOKitKeysPrivate.h>
 #include <IOKit/IOUserClient.h>
 #include <IOKit/IOStatisticsPrivate.h>
 #include <IOKit/IOTimeStamp.h>
 #include <IOKit/IODeviceTreeSupport.h>
+#include <IOKit/IOUserServer.h>
 #include <IOKit/system.h>
 #include <libkern/OSDebug.h>
+#include <DriverKit/OSAction.h>
 #include <sys/proc.h>
 #include <sys/kauth.h>
 #include <sys/codesign.h>
 
 #include <mach/sdt.h>
+#include <os/hash.h>
 
 #if CONFIG_MACF
 
@@ -132,29 +136,37 @@ extern "C" {
 #include <vm/vm_map.h>
 } /* extern "C" */
 
+struct IOMachPortHashList;
+
+static_assert(IKOT_MAX_TYPE <= 255);
+
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
 // IOMachPort maps OSObjects to ports, avoiding adding an ivar to OSObject.
-
 class IOMachPort : public OSObject
 {
-       OSDeclareDefaultStructors(IOMachPort)
+       OSDeclareDefaultStructors(IOMachPort);
 public:
-       OSObject *  object;
+       SLIST_ENTRY(IOMachPort) link;
        ipc_port_t  port;
+       OSObject*   object;
        UInt32      mscount;
        UInt8       holdDestroy;
+       UInt8       type;
+
+       static IOMachPort* withObjectAndType(OSObject *obj, ipc_kobject_type_t type);
+
+       static IOMachPortHashList* bucketForObject(OSObject *obj,
+           ipc_kobject_type_t type);
+
+       static IOMachPort* portForObjectInBucket(IOMachPortHashList *bucket, OSObject *obj, ipc_kobject_type_t type);
 
-       static IOMachPort * portForObject( OSObject * obj,
-           ipc_kobject_type_t type );
        static bool noMoreSendersForObject( OSObject * obj,
            ipc_kobject_type_t type, mach_port_mscount_t * mscount );
        static void releasePortForObject( OSObject * obj,
            ipc_kobject_type_t type );
        static void setHoldDestroy( OSObject * obj, ipc_kobject_type_t type );
 
-       static OSDictionary * dictForType( ipc_kobject_type_t type );
-
        static mach_port_name_t makeSendRightForTask( task_t task,
            io_object_t obj, ipc_kobject_type_t type );
 
@@ -162,119 +174,114 @@ public:
 };
 
 #define super OSObject
-OSDefineMetaClassAndStructors(IOMachPort, OSObject)
+OSDefineMetaClassAndStructorsWithZone(IOMachPort, OSObject, ZC_ZFREE_CLEARMEM)
 
 static IOLock *         gIOObjectPortLock;
+IOLock *                gIOUserServerLock;
+
+SECURITY_READ_ONLY_LATE(const struct io_filter_callbacks *) gIOUCFilterCallbacks;
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
-// not in dictForType() for debugging ease
-static OSDictionary *   gIOObjectPorts;
-static OSDictionary *   gIOConnectPorts;
-static OSDictionary *   gIOIdentifierPorts;
+SLIST_HEAD(IOMachPortHashList, IOMachPort);
 
-OSDictionary *
-IOMachPort::dictForType( ipc_kobject_type_t type )
-{
-       OSDictionary **             dict;
+#if defined(XNU_TARGET_OS_OSX)
+#define PORT_HASH_SIZE 4096
+#else /* defined(!XNU_TARGET_OS_OSX) */
+#define PORT_HASH_SIZE 256
+#endif /* !defined(!XNU_TARGET_OS_OSX) */
 
-       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;
-       }
+IOMachPortHashList gIOMachPortHash[PORT_HASH_SIZE];
 
-       if (0 == *dict) {
-               *dict = OSDictionary::withCapacity( 1 );
+void
+IOMachPortInitialize(void)
+{
+       for (size_t i = 0; i < PORT_HASH_SIZE; i++) {
+               SLIST_INIT(&gIOMachPortHash[i]);
        }
-
-       return *dict;
 }
 
-IOMachPort *
-IOMachPort::portForObject( OSObject * obj,
-    ipc_kobject_type_t type )
+IOMachPortHashList*
+IOMachPort::bucketForObject(OSObject *obj, ipc_kobject_type_t type )
 {
-       IOMachPort *        inst = 0;
-       OSDictionary *      dict;
+       return &gIOMachPortHash[os_hash_kernel_pointer(obj) % PORT_HASH_SIZE];
+}
 
-       IOTakeLock( gIOObjectPortLock);
+IOMachPort*
+IOMachPort::portForObjectInBucket(IOMachPortHashList *bucket, OSObject *obj, ipc_kobject_type_t type)
+{
+       IOMachPort *machPort;
 
-       do {
-               dict = dictForType( type );
-               if (!dict) {
-                       continue;
+       SLIST_FOREACH(machPort, bucket, link) {
+               if (machPort->object == obj && machPort->type == type) {
+                       return machPort;
                }
+       }
+       return NULL;
+}
 
-               if ((inst = (IOMachPort *)
-                   dict->getObject((const OSSymbol *) obj ))) {
-                       inst->mscount++;
-                       inst->retain();
-                       continue;
-               }
+IOMachPort*
+IOMachPort::withObjectAndType(OSObject *obj, ipc_kobject_type_t type)
+{
+       IOMachPort *machPort = NULL;
 
-               inst = new IOMachPort;
-               if (inst && !inst->init()) {
-                       inst = 0;
-                       continue;
-               }
+       machPort = new IOMachPort;
+       if (__improbable(machPort && !machPort->init())) {
+               return NULL;
+       }
 
-               inst->port = iokit_alloc_object_port( obj, type );
-               if (inst->port) {
-                       // retains obj
-                       dict->setObject((const OSSymbol *) obj, inst );
-                       inst->mscount++;
-               } else {
-                       inst->release();
-                       inst = 0;
-               }
-       } while (false);
+       machPort->object = obj;
+       machPort->type = (typeof(machPort->type))type;
+       machPort->port = iokit_alloc_object_port(obj, type);
 
-       IOUnlock( gIOObjectPortLock);
+       obj->taggedRetain(OSTypeID(OSCollection));
+       machPort->mscount++;
 
-       return inst;
+       return machPort;
 }
 
 bool
 IOMachPort::noMoreSendersForObject( OSObject * obj,
     ipc_kobject_type_t type, mach_port_mscount_t * mscount )
 {
-       OSDictionary *      dict;
-       IOMachPort *        machPort;
-       IOUserClient *      uc;
-       bool                destroyed = true;
+       IOMachPort *machPort = NULL;
+       IOUserClient *uc;
+       OSAction *action;
+       bool destroyed = true;
 
-       IOTakeLock( gIOObjectPortLock);
+       IOMachPortHashList *bucket = IOMachPort::bucketForObject(obj, type);
 
-       if ((dict = dictForType( type ))) {
-               obj->retain();
+       obj->retain();
 
-               machPort = (IOMachPort *) dict->getObject((const OSSymbol *) obj );
-               if (machPort) {
-                       destroyed = (machPort->mscount <= *mscount);
-                       if (!destroyed) {
-                               *mscount = machPort->mscount;
-                       } else {
-                               if ((IKOT_IOKIT_CONNECT == type) && (uc = OSDynamicCast(IOUserClient, obj))) {
-                                       uc->noMoreSenders();
-                               }
-                               dict->removeObject((const OSSymbol *) obj );
+       lck_mtx_lock(gIOObjectPortLock);
+
+       machPort = IOMachPort::portForObjectInBucket(bucket, obj, type);
+
+       if (machPort) {
+               destroyed = (machPort->mscount <= *mscount);
+               if (!destroyed) {
+                       *mscount = machPort->mscount;
+                       lck_mtx_unlock(gIOObjectPortLock);
+               } else {
+                       if ((IKOT_IOKIT_CONNECT == type) && (uc = OSDynamicCast(IOUserClient, obj))) {
+                               uc->noMoreSenders();
                        }
+                       SLIST_REMOVE(bucket, machPort, IOMachPort, link);
+
+                       lck_mtx_unlock(gIOObjectPortLock);
+
+                       machPort->release();
+                       obj->taggedRelease(OSTypeID(OSCollection));
                }
-               obj->release();
+       } else {
+               lck_mtx_unlock(gIOObjectPortLock);
        }
 
-       IOUnlock( gIOObjectPortLock);
+       if ((IKOT_UEXT_OBJECT == type) && (action = OSDynamicCast(OSAction, obj))) {
+               action->Aborted();
+       }
+
+       obj->release();
 
        return destroyed;
 }
@@ -283,76 +290,108 @@ void
 IOMachPort::releasePortForObject( OSObject * obj,
     ipc_kobject_type_t type )
 {
-       OSDictionary *      dict;
-       IOMachPort *        machPort;
+       IOMachPort *machPort;
+       IOMachPortHashList *bucket = IOMachPort::bucketForObject(obj, type);
 
        assert(IKOT_IOKIT_CONNECT != type);
 
-       IOTakeLock( gIOObjectPortLock);
+       lck_mtx_lock(gIOObjectPortLock);
 
-       if ((dict = dictForType( type ))) {
+       machPort = IOMachPort::portForObjectInBucket(bucket, obj, type);
+
+       if (machPort && !machPort->holdDestroy) {
                obj->retain();
-               machPort = (IOMachPort *) dict->getObject((const OSSymbol *) obj );
-               if (machPort && !machPort->holdDestroy) {
-                       dict->removeObject((const OSSymbol *) obj );
-               }
+               SLIST_REMOVE(bucket, machPort, IOMachPort, link);
+
+               lck_mtx_unlock(gIOObjectPortLock);
+
+               machPort->release();
+               obj->taggedRelease(OSTypeID(OSCollection));
                obj->release();
+       } else {
+               lck_mtx_unlock(gIOObjectPortLock);
        }
-
-       IOUnlock( gIOObjectPortLock);
 }
 
 void
 IOMachPort::setHoldDestroy( OSObject * obj, ipc_kobject_type_t type )
 {
-       OSDictionary *      dict;
        IOMachPort *        machPort;
 
-       IOLockLock( gIOObjectPortLock );
+       IOMachPortHashList *bucket = IOMachPort::bucketForObject(obj, type);
+       lck_mtx_lock(gIOObjectPortLock);
 
-       if ((dict = dictForType( type ))) {
-               machPort = (IOMachPort *) dict->getObject((const OSSymbol *) obj );
-               if (machPort) {
-                       machPort->holdDestroy = true;
-               }
+       machPort = IOMachPort::portForObjectInBucket(bucket, obj, type);
+
+       if (machPort) {
+               machPort->holdDestroy = true;
        }
 
-       IOLockUnlock( gIOObjectPortLock );
+       lck_mtx_unlock(gIOObjectPortLock);
+}
+
+void
+IOMachPortDestroyUserReferences(OSObject * obj, natural_t type)
+{
+       IOMachPort::releasePortForObject(obj, type);
 }
 
 void
 IOUserClient::destroyUserReferences( OSObject * obj )
 {
+       IOMachPort *machPort;
+
        IOMachPort::releasePortForObject( obj, IKOT_IOKIT_OBJECT );
 
        // panther, 3160200
        // IOMachPort::releasePortForObject( obj, IKOT_IOKIT_CONNECT );
 
-       OSDictionary * dict;
-
-       IOTakeLock( gIOObjectPortLock);
        obj->retain();
+       IOMachPortHashList *bucket = IOMachPort::bucketForObject(obj, IKOT_IOKIT_CONNECT);
+       IOMachPortHashList *mappingBucket = NULL;
 
-       if ((dict = IOMachPort::dictForType( IKOT_IOKIT_CONNECT ))) {
-               IOMachPort * port;
-               port = (IOMachPort *) dict->getObject((const OSSymbol *) obj );
-               if (port) {
-                       IOUserClient * uc;
-                       if ((uc = OSDynamicCast(IOUserClient, obj))) {
-                               uc->noMoreSenders();
-                               if (uc->mappings) {
-                                       dict->setObject((const OSSymbol *) uc->mappings, port);
-                                       iokit_switch_object_port(port->port, uc->mappings, IKOT_IOKIT_CONNECT);
+       lck_mtx_lock(gIOObjectPortLock);
 
-                                       uc->mappings->release();
-                                       uc->mappings = 0;
-                               }
-                       }
-                       dict->removeObject((const OSSymbol *) obj );
+       IOUserClient * uc = OSDynamicCast(IOUserClient, obj);
+       if (uc && uc->mappings) {
+               mappingBucket = IOMachPort::bucketForObject(uc->mappings, IKOT_IOKIT_CONNECT);
+       }
+
+       machPort = IOMachPort::portForObjectInBucket(bucket, obj, IKOT_IOKIT_CONNECT);
+
+       if (machPort == NULL) {
+               lck_mtx_unlock(gIOObjectPortLock);
+               goto end;
+       }
+
+       SLIST_REMOVE(bucket, machPort, IOMachPort, link);
+       obj->taggedRelease(OSTypeID(OSCollection));
+
+       if (uc) {
+               uc->noMoreSenders();
+               if (uc->mappings) {
+                       uc->mappings->taggedRetain(OSTypeID(OSCollection));
+                       machPort->object = uc->mappings;
+                       SLIST_INSERT_HEAD(mappingBucket, machPort, link);
+                       iokit_switch_object_port(machPort->port, uc->mappings, IKOT_IOKIT_CONNECT);
+
+                       lck_mtx_unlock(gIOObjectPortLock);
+
+                       uc->mappings->release();
+                       uc->mappings = NULL;
+               } else {
+                       lck_mtx_unlock(gIOObjectPortLock);
+                       machPort->release();
                }
+       } else {
+               lck_mtx_unlock(gIOObjectPortLock);
+               machPort->release();
        }
+
+
+end:
+
        obj->release();
-       IOUnlock( gIOObjectPortLock);
 }
 
 mach_port_name_t
@@ -373,9 +412,26 @@ IOMachPort::free( void )
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
+static bool
+IOTaskRegistryCompatibility(task_t task)
+{
+       return false;
+}
+
+static void
+IOTaskRegistryCompatibilityMatching(task_t task, OSDictionary * matching)
+{
+       if (!IOTaskRegistryCompatibility(task)) {
+               return;
+       }
+       matching->setObject(gIOCompatibilityMatchKey, kOSBooleanTrue);
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
 class IOUserIterator : public OSIterator
 {
-       OSDeclareDefaultStructors(IOUserIterator)
+       OSDeclareDefaultStructors(IOUserIterator);
 public:
        OSObject    *       userIteratorObject;
        IOLock      *       lock;
@@ -394,7 +450,7 @@ public:
 
 class IOUserNotification : public IOUserIterator
 {
-       OSDeclareDefaultStructors(IOUserNotification)
+       OSDeclareDefaultStructors(IOUserNotification);
 
 #define holdNotify      userIteratorObject
 
@@ -418,13 +474,13 @@ IOUserIterator::withIterator(OSIterator * iter)
        IOUserIterator * me;
 
        if (!iter) {
-               return 0;
+               return NULL;
        }
 
        me = new IOUserIterator;
        if (me && !me->init()) {
                me->release();
-               me = 0;
+               me = NULL;
        }
        if (!me) {
                return me;
@@ -512,7 +568,35 @@ extern "C" {
 // functions called from osfmk/device/iokit_rpc.c
 
 void
-iokit_add_reference( io_object_t obj, ipc_kobject_type_t type )
+iokit_port_object_description(io_object_t obj, kobject_description_t desc)
+{
+       IORegistryEntry    * regEntry;
+       IOUserNotification * __unused noti;
+       _IOServiceNotifier * __unused serviceNoti;
+       OSSerialize        * __unused s;
+
+       if ((regEntry = OSDynamicCast(IORegistryEntry, obj))) {
+               snprintf(desc, KOBJECT_DESCRIPTION_LENGTH, "%s(0x%qx)", obj->getMetaClass()->getClassName(), regEntry->getRegistryEntryID());
+#if DEVELOPMENT || DEBUG
+       } else if ((noti = OSDynamicCast(IOUserNotification, obj))
+           && ((serviceNoti = OSDynamicCast(_IOServiceNotifier, noti->holdNotify)))) {
+               s = OSSerialize::withCapacity((unsigned int) page_size);
+               if (s && serviceNoti->matching->serialize(s)) {
+                       snprintf(desc, KOBJECT_DESCRIPTION_LENGTH, "%s(%s)", obj->getMetaClass()->getClassName(), s->text());
+               }
+               OSSafeReleaseNULL(s);
+#endif /* DEVELOPMENT || DEBUG */
+       } else {
+               snprintf(desc, KOBJECT_DESCRIPTION_LENGTH, "%s", obj->getMetaClass()->getClassName());
+       }
+}
+
+// FIXME: Implementation of these functions are hidden from the static analyzer.
+// As for now, the analyzer doesn't consistently support wrapper functions
+// for retain and release.
+#ifndef __clang_analyzer__
+void
+iokit_add_reference( io_object_t obj, natural_t type )
 {
        IOUserClient * uc;
 
@@ -535,6 +619,7 @@ iokit_remove_reference( io_object_t obj )
                obj->release();
        }
 }
+#endif // __clang_analyzer__
 
 void
 iokit_remove_connect_reference( io_object_t obj )
@@ -581,20 +666,31 @@ IOUserClient::finalizeUserReferences(OSObject * obj)
 ipc_port_t
 iokit_port_for_object( io_object_t obj, ipc_kobject_type_t type )
 {
-       IOMachPort * machPort;
-       ipc_port_t   port;
+       IOMachPort *machPort = NULL;
+       ipc_port_t   port = NULL;
 
-       if ((machPort = IOMachPort::portForObject( obj, type ))) {
-               port = machPort->port;
-               if (port) {
-                       iokit_retain_port( port );
-               }
+       IOMachPortHashList *bucket = IOMachPort::bucketForObject(obj, type);
 
-               machPort->release();
+       lck_mtx_lock(gIOObjectPortLock);
+
+       machPort = IOMachPort::portForObjectInBucket(bucket, obj, type);
+
+       if (__improbable(machPort == NULL)) {
+               machPort = IOMachPort::withObjectAndType(obj, type);
+               if (__improbable(machPort == NULL)) {
+                       goto end;
+               }
+               SLIST_INSERT_HEAD(bucket, machPort, link);
        } else {
-               port = NULL;
+               machPort->mscount++;
        }
 
+       iokit_retain_port(machPort->port);
+       port = machPort->port;
+
+end:
+       lck_mtx_unlock(gIOObjectPortLock);
+
        return port;
 }
 
@@ -605,24 +701,33 @@ iokit_client_died( io_object_t obj, ipc_port_t /* port */,
        IOUserClient *      client;
        IOMemoryMap *       map;
        IOUserNotification * notify;
+       IOUserServerCheckInToken * token;
 
        if (!IOMachPort::noMoreSendersForObject( obj, type, mscount )) {
                return kIOReturnNotReady;
        }
 
-       if (IKOT_IOKIT_CONNECT == type) {
+       switch (type) {
+       case IKOT_IOKIT_CONNECT:
                if ((client = OSDynamicCast( IOUserClient, obj ))) {
                        IOStatisticsClientCall();
-                       IOLockLock(client->lock);
+                       IORWLockWrite(client->lock);
                        client->clientDied();
-                       IOLockUnlock(client->lock);
+                       IORWLockUnlock(client->lock);
                }
-       } else if (IKOT_IOKIT_OBJECT == type) {
+               break;
+       case IKOT_IOKIT_OBJECT:
                if ((map = OSDynamicCast( IOMemoryMap, obj ))) {
                        map->taskDied();
                } else if ((notify = OSDynamicCast( IOUserNotification, obj ))) {
-                       notify->setNotification( 0 );
+                       notify->setNotification( NULL );
                }
+               break;
+       case IKOT_IOKIT_IDENT:
+               if ((token = OSDynamicCast( IOUserServerCheckInToken, obj ))) {
+                       IOUserServerCheckInToken::notifyNoSenders( token );
+               }
+               break;
        }
 
        return kIOReturnSuccess;
@@ -633,7 +738,7 @@ iokit_client_died( io_object_t obj, ipc_port_t /* port */,
 
 class IOServiceUserNotification : public IOUserNotification
 {
-       OSDeclareDefaultStructors(IOServiceUserNotification)
+       OSDeclareDefaultStructors(IOServiceUserNotification);
 
        struct PingMsg {
                mach_msg_header_t               msgHdr;
@@ -643,7 +748,7 @@ class IOServiceUserNotification : public IOUserNotification
        enum { kMaxOutstanding = 1024 };
 
        PingMsg     *       pingMsg;
-       vm_size_t           msgSize;
+       mach_msg_size_t     msgSize;
        OSArray     *       newSet;
        bool                armed;
        bool                ipcLogged;
@@ -666,7 +771,7 @@ public:
 
 class IOServiceMessageUserNotification : public IOUserNotification
 {
-       OSDeclareDefaultStructors(IOServiceMessageUserNotification)
+       OSDeclareDefaultStructors(IOServiceMessageUserNotification);
 
        struct PingMsg {
                mach_msg_header_t               msgHdr;
@@ -676,7 +781,7 @@ class IOServiceMessageUserNotification : public IOUserNotification
        };
 
        PingMsg *           pingMsg;
-       vm_size_t           msgSize;
+       mach_msg_size_t     msgSize;
        uint8_t             clientIs64;
        int                 owningPID;
        bool                ipcLogged;
@@ -685,7 +790,7 @@ public:
 
        virtual bool init( mach_port_t port, natural_t type,
            void * reference, vm_size_t referenceSize,
-           vm_size_t extraSize,
+           mach_msg_size_t extraSize,
            bool clientIs64 );
 
        virtual void free() APPLE_KEXT_OVERRIDE;
@@ -706,8 +811,8 @@ public:
 
 #undef super
 #define super IOUserIterator
-OSDefineMetaClass( IOUserNotification, IOUserIterator )
-OSDefineAbstractStructors( IOUserNotification, IOUserIterator )
+OSDefineMetaClass( IOUserNotification, IOUserIterator );
+OSDefineAbstractStructors( IOUserNotification, IOUserIterator );
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
@@ -717,7 +822,7 @@ IOUserNotification::free( void )
        if (holdNotify) {
                assert(OSDynamicCast(IONotifier, holdNotify));
                ((IONotifier *)holdNotify)->remove();
-               holdNotify = 0;
+               holdNotify = NULL;
        }
        // can't be in handler now
 
@@ -781,7 +886,8 @@ IOServiceUserNotification::init( mach_port_t port, natural_t type,
                return false;
        }
 
-       msgSize = sizeof(PingMsg) - sizeof(OSAsyncReference64) + referenceSize;
+       msgSize = (mach_msg_size_t) (sizeof(PingMsg) - sizeof(OSAsyncReference64) + referenceSize);
+
        pingMsg = (PingMsg *) IOMalloc( msgSize);
        if (!pingMsg) {
                return false;
@@ -912,7 +1018,7 @@ IOServiceUserNotification::copyNextObject()
                result->retain();
                newSet->removeObject( count - 1);
        } else {
-               result = 0;
+               result = NULL;
                armed = true;
        }
 
@@ -929,7 +1035,7 @@ OSDefineMetaClassAndStructors(IOServiceMessageUserNotification, IOUserNotificati
 
 bool
 IOServiceMessageUserNotification::init( mach_port_t port, natural_t type,
-    void * reference, vm_size_t referenceSize, vm_size_t extraSize,
+    void * reference, vm_size_t referenceSize, mach_msg_size_t extraSize,
     bool client64 )
 {
        if (!super::init()) {
@@ -945,7 +1051,7 @@ IOServiceMessageUserNotification::init( mach_port_t port, natural_t type,
        owningPID = proc_selfpid();
 
        extraSize += sizeof(IOServiceInterestContent64);
-       msgSize = sizeof(PingMsg) - sizeof(OSAsyncReference64) + referenceSize;
+       msgSize = (mach_msg_size_t) (sizeof(PingMsg) - sizeof(OSAsyncReference64) + referenceSize);
        pingMsg = (PingMsg *) IOMalloc( msgSize);
        if (!pingMsg) {
                return false;
@@ -963,7 +1069,7 @@ IOServiceMessageUserNotification::init( mach_port_t port, natural_t type,
 
        pingMsg->msgBody.msgh_descriptor_count = 1;
 
-       pingMsg->ports[0].name              = 0;
+       pingMsg->ports[0].name              = NULL;
        pingMsg->ports[0].disposition       = MACH_MSG_TYPE_MAKE_SEND;
        pingMsg->ports[0].type              = MACH_MSG_PORT_DESCRIPTOR;
 
@@ -1020,7 +1126,7 @@ IOServiceMessageUserNotification::handler( void * ref,
        void *                       allocMsg;
        kern_return_t                kr;
        vm_size_t                    argSize;
-       vm_size_t                    thisMsgSize;
+       mach_msg_size_t              thisMsgSize;
        ipc_port_t                   thisPort, providerPort;
        struct PingMsg *             thisMsg;
        IOServiceInterestContent64 * data;
@@ -1050,10 +1156,9 @@ IOServiceMessageUserNotification::handler( void * ref,
        type |= ((argSize & kIOKitNoticationMsgSizeMask) << kIOKitNoticationTypeSizeAdjShift);
        argSize = (argSize + kIOKitNoticationMsgSizeMask) & ~kIOKitNoticationMsgSizeMask;
 
-       thisMsgSize = msgSize
-           + sizeof(IOServiceInterestContent64)
-           - sizeof(data->messageArgument)
-           + argSize;
+       if (os_add3_overflow(msgSize, sizeof(IOServiceInterestContent64) - sizeof(data->messageArgument), argSize, &thisMsgSize)) {
+               return kIOReturnBadArgument;
+       }
 
        if (thisMsgSize > sizeof(stackMsg)) {
                allocMsg = IOMalloc(thisMsgSize);
@@ -1062,7 +1167,7 @@ IOServiceMessageUserNotification::handler( void * ref,
                }
                thisMsg = (typeof(thisMsg))allocMsg;
        } else {
-               allocMsg = 0;
+               allocMsg = NULL;
                thisMsg  = (typeof(thisMsg))stackMsg;
        }
 
@@ -1116,7 +1221,7 @@ IOServiceMessageUserNotification::handler( void * ref,
 OSObject *
 IOServiceMessageUserNotification::getNextObject()
 {
-       return 0;
+       return NULL;
 }
 
 OSObject *
@@ -1138,18 +1243,34 @@ IOUserClient::initialize( void )
 {
        gIOObjectPortLock       = IOLockAlloc();
        gIOUserClientOwnersLock = IOLockAlloc();
+       gIOUserServerLock       = IOLockAlloc();
        assert(gIOObjectPortLock && gIOUserClientOwnersLock);
+
+#if IOTRACKING
+       IOTrackingQueueCollectUser(IOUserIterator::gMetaClass.getTracking());
+       IOTrackingQueueCollectUser(IOServiceMessageUserNotification::gMetaClass.getTracking());
+       IOTrackingQueueCollectUser(IOServiceUserNotification::gMetaClass.getTracking());
+       IOTrackingQueueCollectUser(IOUserClient::gMetaClass.getTracking());
+       IOTrackingQueueCollectUser(IOMachPort::gMetaClass.getTracking());
+#endif /* IOTRACKING */
 }
 
 void
+#if __LP64__
+__attribute__((__noreturn__))
+#endif
 IOUserClient::setAsyncReference(OSAsyncReference asyncRef,
     mach_port_t wakePort,
     void *callback, void *refcon)
 {
+#if __LP64__
+       panic("setAsyncReference not valid for 64b");
+#else
        asyncRef[kIOAsyncReservedIndex]      = ((uintptr_t) wakePort)
            | (kIOUCAsync0Flags & asyncRef[kIOAsyncReservedIndex]);
        asyncRef[kIOAsyncCalloutFuncIndex]   = (uintptr_t) callback;
        asyncRef[kIOAsyncCalloutRefconIndex] = (uintptr_t) refcon;
+#endif
 }
 
 void
@@ -1178,7 +1299,7 @@ static OSDictionary *
 CopyConsoleUser(UInt32 uid)
 {
        OSArray * array;
-       OSDictionary * user = 0;
+       OSDictionary * user = NULL;
 
        if ((array = OSDynamicCast(OSArray,
            IORegistryEntry::getRegistryRoot()->copyProperty(gIOConsoleUsersKey)))) {
@@ -1202,7 +1323,7 @@ static OSDictionary *
 CopyUserOnConsole(void)
 {
        OSArray * array;
-       OSDictionary * user = 0;
+       OSDictionary * user = NULL;
 
        if ((array = OSDynamicCast(OSArray,
            IORegistryEntry::getRegistryRoot()->copyProperty(gIOConsoleUsersKey)))) {
@@ -1334,34 +1455,42 @@ IOUserClient::clientHasPrivilege( void * securityToken,
 
        return kr;
 }
-
-OSObject *
-IOUserClient::copyClientEntitlement( task_t task,
-    const char * entitlement )
-{
 #define MAX_ENTITLEMENTS_LEN    (128 * 1024)
 
+OSDictionary *
+IOUserClient::copyClientEntitlements(task_t task)
+{
        proc_t p = NULL;
        pid_t pid = 0;
-       char procname[MAXCOMLEN + 1] = "";
        size_t len = 0;
        void *entitlements_blob = NULL;
-       char *entitlements_data = NULL;
-       OSObject *entitlements_obj = NULL;
        OSDictionary *entitlements = NULL;
-       OSString *errorString = NULL;
-       OSObject *value = NULL;
 
        p = (proc_t)get_bsdtask_info(task);
        if (p == NULL) {
-               goto fail;
+               return NULL;
        }
        pid = proc_pid(p);
-       proc_name(pid, procname, (int)sizeof(procname));
+
+       if (cs_entitlements_dictionary_copy(p, (void **)&entitlements) == 0) {
+               if (entitlements) {
+                       return entitlements;
+               }
+       }
 
        if (cs_entitlements_blob_get(p, &entitlements_blob, &len) != 0) {
-               goto fail;
+               return NULL;
        }
+       return IOUserClient::copyEntitlementsFromBlob(entitlements_blob, len);
+}
+
+OSDictionary *
+IOUserClient::copyEntitlementsFromBlob(void *entitlements_blob, size_t len)
+{
+       char *entitlements_data = NULL;
+       OSObject *entitlements_obj = NULL;
+       OSString *errorString = NULL;
+       OSDictionary *entitlements = NULL;
 
        if (len <= offsetof(CS_GenericBlob, data)) {
                goto fail;
@@ -1373,7 +1502,8 @@ IOUserClient::copyClientEntitlement( task_t task,
         */
        len -= offsetof(CS_GenericBlob, data);
        if (len > MAX_ENTITLEMENTS_LEN) {
-               IOLog("failed to parse entitlements for %s[%u]: %lu bytes of entitlements exceeds maximum of %u\n", procname, pid, len, MAX_ENTITLEMENTS_LEN);
+               IOLog("failed to parse entitlements: %lu bytes of entitlements exceeds maximum of %u\n",
+                   len, MAX_ENTITLEMENTS_LEN);
                goto fail;
        }
 
@@ -1391,7 +1521,7 @@ IOUserClient::copyClientEntitlement( task_t task,
 
        entitlements_obj = OSUnserializeXML(entitlements_data, len + 1, &errorString);
        if (errorString != NULL) {
-               IOLog("failed to parse entitlements for %s[%u]: %s\n", procname, pid, errorString->getCStringNoCopy());
+               IOLog("failed to parse entitlements: %s\n", errorString->getCStringNoCopy());
                goto fail;
        }
        if (entitlements_obj == NULL) {
@@ -1402,12 +1532,7 @@ IOUserClient::copyClientEntitlement( task_t task,
        if (entitlements == NULL) {
                goto fail;
        }
-
-       /* Fetch the entitlement value from the dictionary. */
-       value = entitlements->getObject(entitlement);
-       if (value != NULL) {
-               value->retain();
-       }
+       entitlements_obj = NULL;
 
 fail:
        if (entitlements_data != NULL) {
@@ -1419,6 +1544,64 @@ fail:
        if (errorString != NULL) {
                errorString->release();
        }
+       return entitlements;
+}
+
+OSDictionary *
+IOUserClient::copyClientEntitlementsVnode(vnode_t vnode, off_t offset)
+{
+       size_t len = 0;
+       void *entitlements_blob = NULL;
+
+       if (cs_entitlements_blob_get_vnode(vnode, offset, &entitlements_blob, &len) != 0) {
+               return NULL;
+       }
+       return IOUserClient::copyEntitlementsFromBlob(entitlements_blob, len);
+}
+
+OSObject *
+IOUserClient::copyClientEntitlement( task_t task,
+    const char * entitlement )
+{
+       OSDictionary *entitlements;
+       OSObject *value;
+
+       entitlements = copyClientEntitlements(task);
+       if (entitlements == NULL) {
+               return NULL;
+       }
+
+       /* Fetch the entitlement value from the dictionary. */
+       value = entitlements->getObject(entitlement);
+       if (value != NULL) {
+               value->retain();
+       }
+
+       entitlements->release();
+       return value;
+}
+
+OSObject *
+IOUserClient::copyClientEntitlementVnode(
+       struct vnode *vnode,
+       off_t offset,
+       const char *entitlement)
+{
+       OSDictionary *entitlements;
+       OSObject *value;
+
+       entitlements = copyClientEntitlementsVnode(vnode, offset);
+       if (entitlements == NULL) {
+               return NULL;
+       }
+
+       /* Fetch the entitlement value from the dictionary. */
+       value = entitlements->getObject(entitlement);
+       if (value != NULL) {
+               value->retain();
+       }
+
+       entitlements->release();
        return value;
 }
 
@@ -1472,7 +1655,7 @@ bool
 IOUserClient::reserve()
 {
        if (!reserved) {
-               reserved = IONew(ExpansionData, 1);
+               reserved = IONewZero(ExpansionData, 1);
                if (!reserved) {
                        return false;
                }
@@ -1523,6 +1706,9 @@ IOUserClient::registerOwner(task_t task)
                        owner->uc   = this;
                        queue_enter_first(&owners, owner, IOUserClientOwner *, ucLink);
                        queue_enter_first(task_io_user_clients(task), owner, IOUserClientOwner *, taskLink);
+                       if (messageAppSuspended) {
+                               task_set_message_app_suspended(task, true);
+                       }
                }
        }
 
@@ -1535,13 +1721,25 @@ void
 IOUserClient::noMoreSenders(void)
 {
        IOUserClientOwner * owner;
+       IOUserClientOwner * iter;
+       queue_head_t      * taskque;
+       bool                hasMessageAppSuspended;
 
        IOLockLock(gIOUserClientOwnersLock);
 
        if (owners.next) {
                while (!queue_empty(&owners)) {
                        owner = (IOUserClientOwner *)(void *) queue_first(&owners);
-                       queue_remove(task_io_user_clients(owner->task), owner, IOUserClientOwner *, taskLink);
+                       taskque = task_io_user_clients(owner->task);
+                       queue_remove(taskque, owner, IOUserClientOwner *, taskLink);
+                       hasMessageAppSuspended = false;
+                       queue_iterate(taskque, iter, IOUserClientOwner *, taskLink) {
+                               hasMessageAppSuspended = iter->uc->messageAppSuspended;
+                               if (hasMessageAppSuspended) {
+                                       break;
+                               }
+                       }
+                       task_set_message_app_suspended(owner->task, hasMessageAppSuspended);
                        queue_remove(&owners, owner, IOUserClientOwner *, ucLink);
                        IODelete(owner, IOUserClientOwner, 1);
                }
@@ -1551,6 +1749,55 @@ IOUserClient::noMoreSenders(void)
        IOLockUnlock(gIOUserClientOwnersLock);
 }
 
+
+extern "C" void
+iokit_task_app_suspended_changed(task_t task)
+{
+       queue_head_t      * taskque;
+       IOUserClientOwner * owner;
+       OSSet             * set;
+
+       IOLockLock(gIOUserClientOwnersLock);
+
+       taskque = task_io_user_clients(task);
+       set = NULL;
+       queue_iterate(taskque, owner, IOUserClientOwner *, taskLink) {
+               if (!owner->uc->messageAppSuspended) {
+                       continue;
+               }
+               if (!set) {
+                       set = OSSet::withCapacity(4);
+                       if (!set) {
+                               break;
+                       }
+               }
+               set->setObject(owner->uc);
+       }
+
+       IOLockUnlock(gIOUserClientOwnersLock);
+
+       if (set) {
+               set->iterateObjects(^bool (OSObject * obj) {
+                       IOUserClient      * uc;
+
+                       uc = (typeof(uc))obj;
+#if 0
+                       {
+                               OSString          * str;
+                               str = IOCopyLogNameForPID(task_pid(task));
+                               IOLog("iokit_task_app_suspended_changed(%s) %s %d\n", str ? str->getCStringNoCopy() : "",
+                               uc->getName(), task_is_app_suspended(task));
+                               OSSafeReleaseNULL(str);
+                       }
+#endif
+                       uc->message(kIOMessageTaskAppSuspendedChange, NULL);
+
+                       return false;
+               });
+               set->release();
+       }
+}
+
 extern "C" kern_return_t
 iokit_task_terminate(task_t task)
 {
@@ -1595,6 +1842,44 @@ iokit_task_terminate(task_t task)
        return KERN_SUCCESS;
 }
 
+struct IOUCFilterPolicy {
+       task_t             task;
+       io_filter_policy_t filterPolicy;
+       IOUCFilterPolicy * next;
+};
+
+io_filter_policy_t
+IOUserClient::filterForTask(task_t task, io_filter_policy_t addFilterPolicy)
+{
+       IOUCFilterPolicy * elem;
+       io_filter_policy_t filterPolicy;
+
+       filterPolicy = 0;
+       IOLockLock(filterLock);
+
+       for (elem = reserved->filterPolicies; elem && (elem->task != task); elem = elem->next) {
+       }
+
+       if (elem) {
+               if (addFilterPolicy) {
+                       assert(addFilterPolicy == elem->filterPolicy);
+               }
+               filterPolicy = elem->filterPolicy;
+       } else if (addFilterPolicy) {
+               elem = IONewZero(IOUCFilterPolicy, 1);
+               if (elem) {
+                       elem->task               = task;
+                       elem->filterPolicy       = addFilterPolicy;
+                       elem->next               = reserved->filterPolicies;
+                       reserved->filterPolicies = elem;
+                       filterPolicy = addFilterPolicy;
+               }
+       }
+
+       IOLockUnlock(filterLock);
+       return filterPolicy;
+}
+
 void
 IOUserClient::free()
 {
@@ -1602,7 +1887,10 @@ IOUserClient::free()
                mappings->release();
        }
        if (lock) {
-               IOLockFree(lock);
+               IORWLockFree(lock);
+       }
+       if (filterLock) {
+               IOLockFree(filterLock);
        }
 
        IOStatisticsUnregisterCounter();
@@ -1611,6 +1899,15 @@ IOUserClient::free()
        assert(!owners.prev);
 
        if (reserved) {
+               IOUCFilterPolicy * elem;
+               IOUCFilterPolicy * nextElem;
+               for (elem = reserved->filterPolicies; elem; elem = nextElem) {
+                       nextElem = elem->next;
+                       if (elem->filterPolicy && gIOUCFilterCallbacks->io_filter_release) {
+                               gIOUCFilterCallbacks->io_filter_release(elem->filterPolicy);
+                       }
+                       IODelete(elem, IOUCFilterPolicy, 1);
+               }
                IODelete(reserved, ExpansionData, 1);
        }
 
@@ -1638,7 +1935,7 @@ IOUserClient::clientClose( void )
 IOService *
 IOUserClient::getService( void )
 {
-       return 0;
+       return NULL;
 }
 
 IOReturn
@@ -1680,6 +1977,17 @@ IOUserClient::clientMemoryForType( UInt32 type,
        return kIOReturnUnsupported;
 }
 
+IOReturn
+IOUserClient::clientMemoryForType( UInt32 type,
+    IOOptionBits * options,
+    OSSharedPtr<IOMemoryDescriptor>& memory )
+{
+       IOMemoryDescriptor* memoryRaw = nullptr;
+       IOReturn result = clientMemoryForType(type, options, &memoryRaw);
+       memory.reset(memoryRaw, OSNoRetain);
+       return result;
+}
+
 #if !__LP64__
 IOMemoryMap *
 IOUserClient::mapClientMemory(
@@ -1701,8 +2009,8 @@ IOUserClient::mapClientMemory64(
 {
        IOReturn            err;
        IOOptionBits        options = 0;
-       IOMemoryDescriptor * memory = 0;
-       IOMemoryMap *       map = 0;
+       IOMemoryDescriptor * memory = NULL;
+       IOMemoryMap *       map = NULL;
 
        err = clientMemoryForType((UInt32) type, &options, &memory );
 
@@ -1763,6 +2071,16 @@ IOUserClient::copyObjectForPortNameInTask(task_t task, mach_port_name_t port_nam
        return object ? kIOReturnSuccess : kIOReturnIPCError;
 }
 
+IOReturn
+IOUserClient::copyObjectForPortNameInTask(task_t task, mach_port_name_t port_name,
+    OSSharedPtr<OSObject>& obj)
+{
+       OSObject* objRaw = NULL;
+       IOReturn result = copyObjectForPortNameInTask(task, port_name, &objRaw);
+       obj.reset(objRaw, OSNoRetain);
+       return result;
+}
+
 IOReturn
 IOUserClient::adjustPortNameReferencesInTask(task_t task, mach_port_name_t port_name, mach_port_delta_t delta)
 {
@@ -1772,13 +2090,13 @@ IOUserClient::adjustPortNameReferencesInTask(task_t task, mach_port_name_t port_
 IOExternalMethod *
 IOUserClient::getExternalMethodForIndex( UInt32 /* index */)
 {
-       return 0;
+       return NULL;
 }
 
 IOExternalAsyncMethod *
 IOUserClient::getExternalAsyncMethodForIndex( UInt32 /* index */)
 {
-       return 0;
+       return NULL;
 }
 
 IOExternalTrap *
@@ -1806,6 +2124,16 @@ getTargetAndMethodForIndex(IOService **targetP, UInt32 index)
        return method;
 }
 
+IOExternalMethod *
+IOUserClient::
+getTargetAndMethodForIndex(OSSharedPtr<IOService>& targetP, UInt32 index)
+{
+       IOService* targetPRaw = NULL;
+       IOExternalMethod* result = getTargetAndMethodForIndex(&targetPRaw, index);
+       targetP.reset(targetPRaw, OSRetain);
+       return result;
+}
+
 IOExternalAsyncMethod *
 IOUserClient::
 getAsyncTargetAndMethodForIndex(IOService ** targetP, UInt32 index)
@@ -1819,6 +2147,16 @@ getAsyncTargetAndMethodForIndex(IOService ** targetP, UInt32 index)
        return method;
 }
 
+IOExternalAsyncMethod *
+IOUserClient::
+getAsyncTargetAndMethodForIndex(OSSharedPtr<IOService>& targetP, UInt32 index)
+{
+       IOService* targetPRaw = NULL;
+       IOExternalAsyncMethod* result = getAsyncTargetAndMethodForIndex(&targetPRaw, index);
+       targetP.reset(targetPRaw, OSRetain);
+       return result;
+}
+
 IOExternalTrap *
 IOUserClient::
 getTargetAndTrapForIndex(IOService ** targetP, UInt32 index)
@@ -1930,7 +2268,7 @@ IOUserClient::_sendAsyncResult64(OSAsyncReference64 reference,
        replyMsg.msgHdr.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND /*remote*/,
            0 /*local*/);
        replyMsg.msgHdr.msgh_remote_port = replyPort;
-       replyMsg.msgHdr.msgh_local_port  = 0;
+       replyMsg.msgHdr.msgh_local_port  = NULL;
        replyMsg.msgHdr.msgh_id          = kOSNotificationMessageID;
        if (kIOUCAsync64Flag & reference[0]) {
                replyMsg.msgHdr.msgh_size =
@@ -1939,7 +2277,8 @@ IOUserClient::_sendAsyncResult64(OSAsyncReference64 reference,
                replyMsg.m.msg64.notifyHdr.size = sizeof(IOAsyncCompletionContent)
                    + numArgs * sizeof(io_user_reference_t);
                replyMsg.m.msg64.notifyHdr.type = kIOAsyncCompletionNotificationType;
-               bcopy(reference, replyMsg.m.msg64.notifyHdr.reference, sizeof(OSAsyncReference64));
+               /* Copy reference except for reference[0], which is left as 0 from the earlier bzero */
+               bcopy(&reference[1], &replyMsg.m.msg64.notifyHdr.reference[1], sizeof(OSAsyncReference64) - sizeof(reference[0]));
 
                replyMsg.m.msg64.asyncContent.result = result;
                if (numArgs) {
@@ -1956,7 +2295,8 @@ IOUserClient::_sendAsyncResult64(OSAsyncReference64 reference,
                    + numArgs * sizeof(uint32_t);
                replyMsg.m.msg32.notifyHdr.type = kIOAsyncCompletionNotificationType;
 
-               for (idx = 0; idx < kOSAsyncRefCount; idx++) {
+               /* Skip reference[0] which is left as 0 from the earlier bzero */
+               for (idx = 1; idx < kOSAsyncRefCount; idx++) {
                        replyMsg.m.msg32.notifyHdr.reference[idx] = REF32(reference[idx]);
                }
 
@@ -2077,7 +2417,7 @@ is_io_object_get_superclass(
        }
 
        ret = kIOReturnNotFound;
-       meta = 0;
+       meta = NULL;
        do{
                name = OSSymbol::withCString(obj_name);
                if (!name) {
@@ -2128,7 +2468,7 @@ is_io_object_get_bundle_identifier(
        }
 
        ret = kIOReturnNotFound;
-       meta = 0;
+       meta = NULL;
        do{
                name = OSSymbol::withCString(obj_name);
                if (!name) {
@@ -2169,7 +2509,7 @@ is_io_object_conforms_to(
                return kIOReturnBadArgument;
        }
 
-       *conforms = (0 != object->metaCast( className ));
+       *conforms = (NULL != object->metaCast( className ));
 
        return kIOReturnSuccess;
 }
@@ -2245,7 +2585,6 @@ is_io_iterator_is_valid(
        return kIOReturnSuccess;
 }
 
-
 static kern_return_t
 internal_io_service_match_property_table(
        io_service_t _service,
@@ -2260,9 +2599,12 @@ internal_io_service_match_property_table(
        OSDictionary *      dict;
 
        assert(matching_size);
+
+
        obj = OSUnserializeXML(matching, matching_size);
 
        if ((dict = OSDynamicCast( OSDictionary, obj))) {
+               IOTaskRegistryCompatibilityMatching(current_task(), dict);
                *matches = service->passiveMatch( dict );
                kr = kIOReturnSuccess;
        } else {
@@ -2343,6 +2685,7 @@ internal_io_service_get_matching_services(
        obj = OSUnserializeXML(matching, matching_size);
 
        if ((dict = OSDynamicCast( OSDictionary, obj))) {
+               IOTaskRegistryCompatibilityMatching(current_task(), dict);
                *existing = IOUserIterator::withIterator(IOService::getMatchingServices( dict ));
                kr = kIOReturnSuccess;
        } else {
@@ -2385,7 +2728,7 @@ is_io_service_get_matching_services_ool(
        if (KERN_SUCCESS == kr) {
                // must return success after vm_map_copyout() succeeds
                // and mig will copy out objects on success
-               *existing = 0;
+               *existing = NULL;
                *result = internal_io_service_get_matching_services(master_port,
                    (const char *) data, matchingCnt, existing);
                vm_deallocate( kernel_map, data, matchingCnt );
@@ -2425,6 +2768,7 @@ internal_io_service_get_matching_service(
        obj = OSUnserializeXML(matching, matching_size);
 
        if ((dict = OSDynamicCast( OSDictionary, obj))) {
+               IOTaskRegistryCompatibilityMatching(current_task(), dict);
                *service = IOService::copyMatchingService( dict );
                kr = *service ? kIOReturnSuccess : kIOReturnNotFound;
        } else {
@@ -2467,7 +2811,7 @@ is_io_service_get_matching_service_ool(
        if (KERN_SUCCESS == kr) {
                // must return success after vm_map_copyout() succeeds
                // and mig will copy out objects on success
-               *service = 0;
+               *service = NULL;
                *result = internal_io_service_get_matching_service(master_port,
                    (const char *) data, matchingCnt, service );
                vm_deallocate( kernel_map, data, matchingCnt );
@@ -2499,12 +2843,13 @@ internal_io_service_add_notification(
        bool client64,
        io_object_t * notification )
 {
-       IOServiceUserNotification * userNotify = 0;
-       IONotifier *                notify = 0;
+       IOServiceUserNotification * userNotify = NULL;
+       IONotifier *                notify = NULL;
        const OSSymbol *            sym;
+       OSObject *                  obj;
        OSDictionary *              dict;
        IOReturn                    err;
-       unsigned long int           userMsgType;
+       natural_t                   userMsgType;
 
        if (master_port != master_device_port) {
                return kIOReturnNotPrivileged;
@@ -2522,11 +2867,13 @@ internal_io_service_add_notification(
                }
 
                assert(matching_size);
-               dict = OSDynamicCast(OSDictionary, OSUnserializeXML(matching, matching_size));
+               obj = OSUnserializeXML(matching, matching_size);
+               dict = OSDynamicCast(OSDictionary, obj);
                if (!dict) {
                        err = kIOReturnBadArgument;
                        continue;
                }
+               IOTaskRegistryCompatibilityMatching(current_task(), dict);
 
                if ((sym == gIOPublishNotification)
                    || (sym == gIOFirstPublishNotification)) {
@@ -2546,7 +2893,7 @@ internal_io_service_add_notification(
                if (userNotify && !userNotify->init( port, userMsgType,
                    reference, referenceSize, client64)) {
                        userNotify->release();
-                       userNotify = 0;
+                       userNotify = NULL;
                }
                if (!userNotify) {
                        continue;
@@ -2566,14 +2913,14 @@ internal_io_service_add_notification(
        if ((kIOReturnSuccess != err) && userNotify) {
                userNotify->invalidatePort();
                userNotify->release();
-               userNotify = 0;
+               userNotify = NULL;
        }
 
        if (sym) {
                sym->release();
        }
-       if (dict) {
-               dict->release();
+       if (obj) {
+               obj->release();
        }
 
        return err;
@@ -2683,7 +3030,7 @@ internal_io_service_add_notification_ool(
        if (KERN_SUCCESS == kr) {
                // must return success after vm_map_copyout() succeeds
                // and mig will copy out objects on success
-               *notification = 0;
+               *notification = NULL;
                *result = internal_io_service_add_notification( master_port, notification_type,
                    (char *) data, matchingCnt, wake_port, reference, referenceSize, client64, notification );
                vm_deallocate( kernel_map, data, matchingCnt );
@@ -2770,8 +3117,8 @@ internal_io_service_add_interest_notification(
        bool client64,
        io_object_t * notification )
 {
-       IOServiceMessageUserNotification *  userNotify = 0;
-       IONotifier *                        notify = 0;
+       IOServiceMessageUserNotification *  userNotify = NULL;
+       IONotifier *                        notify = NULL;
        const OSSymbol *                    sym;
        IOReturn                            err;
 
@@ -2787,7 +3134,7 @@ internal_io_service_add_interest_notification(
                            kIOUserNotifyMaxMessageSize,
                            client64 )) {
                                userNotify->release();
-                               userNotify = 0;
+                               userNotify = NULL;
                        }
                        if (!userNotify) {
                                continue;
@@ -2810,7 +3157,7 @@ internal_io_service_add_interest_notification(
        if ((kIOReturnSuccess != err) && userNotify) {
                userNotify->invalidatePort();
                userNotify->release();
-               userNotify = 0;
+               userNotify = NULL;
        }
 
        return err;
@@ -2881,11 +3228,16 @@ is_io_connect_get_notification_semaphore(
        natural_t notification_type,
        semaphore_t *semaphore )
 {
+       IOReturn ret;
        CHECK( IOUserClient, connection, client );
 
        IOStatisticsClientCall();
-       return client->getNotificationSemaphore((UInt32) notification_type,
-                  semaphore );
+       IORWLockWrite(client->lock);
+       ret = client->getNotificationSemaphore((UInt32) notification_type,
+           semaphore );
+       IORWLockUnlock(client->lock);
+
+       return ret;
 }
 
 /* Routine io_registry_get_root_entry */
@@ -2990,6 +3342,20 @@ is_io_registry_entry_from_path(
 
        entry = IORegistryEntry::fromPath( path );
 
+       if (!entry && IOTaskRegistryCompatibility(current_task())) {
+               OSDictionary * matching;
+               const OSObject * objects[2] = { kOSBooleanTrue, NULL };
+               const OSSymbol * keys[2]    = { gIOCompatibilityMatchKey, gIOPathMatchKey };
+
+               objects[1] = OSString::withCStringNoCopy(path);
+               matching = OSDictionary::withObjects(objects, keys, 2, 2);
+               if (matching) {
+                       entry = IOService::copyMatchingService(matching);
+               }
+               OSSafeReleaseNULL(matching);
+               OSSafeReleaseNULL(objects[1]);
+       }
+
        *registry_entry = entry;
 
        return kIOReturnSuccess;
@@ -3017,7 +3383,7 @@ is_io_registry_entry_from_path_ool(
        }
 
        map_data = 0;
-       entry    = 0;
+       entry    = NULL;
        res = err = KERN_SUCCESS;
        if (path[0]) {
                cpath = path;
@@ -3158,7 +3524,7 @@ is_io_registry_entry_get_name_in_plane(
        if (planeName[0]) {
                plane = IORegistryEntry::getPlane( planeName );
        } else {
-               plane = 0;
+               plane = NULL;
        }
 
        strncpy( name, entry->getName( plane), sizeof(io_name_t));
@@ -3179,7 +3545,7 @@ is_io_registry_entry_get_location_in_plane(
        if (planeName[0]) {
                plane = IORegistryEntry::getPlane( planeName );
        } else {
-               plane = 0;
+               plane = NULL;
        }
 
        const char * cstr = entry->getLocation( plane );
@@ -3205,6 +3571,31 @@ is_io_registry_entry_get_registry_entry_id(
        return kIOReturnSuccess;
 }
 
+
+static OSObject *
+IOCopyPropertyCompatible(IORegistryEntry * regEntry, const char * name)
+{
+       OSObject     * obj;
+       OSObject     * compatProps;
+       OSDictionary * props;
+
+       obj = regEntry->copyProperty(name);
+       if (!obj
+           && IOTaskRegistryCompatibility(current_task())
+           && (compatProps = regEntry->copyProperty(gIOCompatibilityPropertiesKey))) {
+               props = OSDynamicCast(OSDictionary, compatProps);
+               if (props) {
+                       obj = props->getObject(name);
+                       if (obj) {
+                               obj->retain();
+                       }
+               }
+               compatProps->release();
+       }
+
+       return obj;
+}
+
 /* Routine io_registry_entry_get_property */
 kern_return_t
 is_io_registry_entry_get_property_bytes(
@@ -3220,7 +3611,7 @@ is_io_registry_entry_get_property_bytes(
        OSNumber    *       off;
        UInt64              offsetBytes;
        unsigned int        len = 0;
-       const void *        bytes = 0;
+       const void *        bytes = NULL;
        IOReturn            ret = kIOReturnSuccess;
 
        CHECK( IORegistryEntry, registry_entry, entry );
@@ -3231,7 +3622,7 @@ is_io_registry_entry_get_property_bytes(
        }
 #endif
 
-       obj = entry->copyProperty(property_name);
+       obj = IOCopyPropertyCompatible(entry, property_name);
        if (!obj) {
                return kIOReturnNoResources;
        }
@@ -3288,7 +3679,7 @@ is_io_registry_entry_get_property(
        mach_msg_type_number_t *propertiesCnt )
 {
        kern_return_t       err;
-       vm_size_t           len;
+       unsigned int        len;
        OSObject *          obj;
 
        CHECK( IORegistryEntry, registry_entry, entry );
@@ -3299,7 +3690,7 @@ is_io_registry_entry_get_property(
        }
 #endif
 
-       obj = entry->copyProperty(property_name);
+       obj = IOCopyPropertyCompatible(entry, property_name);
        if (!obj) {
                return kIOReturnNotFound;
        }
@@ -3335,7 +3726,7 @@ is_io_registry_entry_get_property_recursively(
        mach_msg_type_number_t *propertiesCnt )
 {
        kern_return_t       err;
-       vm_size_t           len;
+       unsigned int        len;
        OSObject *          obj;
 
        CHECK( IORegistryEntry, registry_entry, entry );
@@ -3404,7 +3795,7 @@ GetPropertiesEditor(void                  * reference,
        }
        if (ref->root == container) {
                if (0 != mac_iokit_check_get_property(ref->cred, ref->entry, name->getCStringNoCopy())) {
-                       value = 0;
+                       value = NULL;
                }
        }
        if (value) {
@@ -3415,18 +3806,21 @@ GetPropertiesEditor(void                  * reference,
 
 #endif /* CONFIG_MACF */
 
-/* Routine io_registry_entry_get_properties */
+/* Routine io_registry_entry_get_properties_bin_buf */
 kern_return_t
-is_io_registry_entry_get_properties_bin(
+is_io_registry_entry_get_properties_bin_buf(
        io_object_t registry_entry,
+       mach_vm_address_t buf,
+       mach_vm_size_t *bufsize,
        io_buf_ptr_t *properties,
        mach_msg_type_number_t *propertiesCnt)
 {
-       kern_return_t              err = kIOReturnSuccess;
-       vm_size_t                  len;
+       kern_return_t          err = kIOReturnSuccess;
+       unsigned int           len;
+       OSObject             * compatProperties;
        OSSerialize          * s;
-       OSSerialize::Editor    editor = 0;
-       void                 * editRef = 0;
+       OSSerialize::Editor    editor = NULL;
+       void                 * editRef = NULL;
 
        CHECK(IORegistryEntry, registry_entry, entry);
 
@@ -3437,7 +3831,7 @@ is_io_registry_entry_get_properties_bin(
                editRef   = &ref;
                ref.cred  = kauth_cred_get();
                ref.entry = entry;
-               ref.root  = 0;
+               ref.root  = NULL;
        }
 #endif
 
@@ -3446,32 +3840,75 @@ is_io_registry_entry_get_properties_bin(
                return kIOReturnNoMemory;
        }
 
-       if (!entry->serializeProperties(s)) {
+       if (IOTaskRegistryCompatibility(current_task())
+           && (compatProperties = entry->copyProperty(gIOCompatibilityPropertiesKey))) {
+               OSDictionary * dict;
+
+               dict = entry->dictionaryWithProperties();
+               if (!dict) {
+                       err = kIOReturnNoMemory;
+               } else {
+                       dict->removeObject(gIOCompatibilityPropertiesKey);
+                       dict->merge(OSDynamicCast(OSDictionary, compatProperties));
+                       if (!dict->serialize(s)) {
+                               err = kIOReturnUnsupported;
+                       }
+                       dict->release();
+               }
+               compatProperties->release();
+       } else if (!entry->serializeProperties(s)) {
                err = kIOReturnUnsupported;
        }
 
        if (kIOReturnSuccess == err) {
                len = s->getLength();
-               *propertiesCnt = len;
-               err = copyoutkdata(s->text(), len, properties);
+               if (buf && bufsize && len <= *bufsize) {
+                       *bufsize = len;
+                       *propertiesCnt = 0;
+                       *properties = nullptr;
+                       if (copyout(s->text(), buf, len)) {
+                               err = kIOReturnVMError;
+                       } else {
+                               err = kIOReturnSuccess;
+                       }
+               } else {
+                       if (bufsize) {
+                               *bufsize = 0;
+                       }
+                       *propertiesCnt = len;
+                       err = copyoutkdata( s->text(), len, properties );
+               }
        }
        s->release();
 
        return err;
 }
 
-/* Routine io_registry_entry_get_property_bin */
+/* Routine io_registry_entry_get_properties_bin */
 kern_return_t
-is_io_registry_entry_get_property_bin(
+is_io_registry_entry_get_properties_bin(
+       io_object_t registry_entry,
+       io_buf_ptr_t *properties,
+       mach_msg_type_number_t *propertiesCnt)
+{
+       return is_io_registry_entry_get_properties_bin_buf(registry_entry,
+                  0, NULL, properties, propertiesCnt);
+}
+
+/* Routine io_registry_entry_get_property_bin_buf */
+kern_return_t
+is_io_registry_entry_get_property_bin_buf(
        io_object_t registry_entry,
        io_name_t plane,
        io_name_t property_name,
        uint32_t options,
+       mach_vm_address_t buf,
+       mach_vm_size_t *bufsize,
        io_buf_ptr_t *properties,
        mach_msg_type_number_t *propertiesCnt )
 {
        kern_return_t       err;
-       vm_size_t           len;
+       unsigned int        len;
        OSObject *          obj;
        const OSSymbol *    sym;
 
@@ -3492,10 +3929,24 @@ is_io_registry_entry_get_property_bin(
                obj = entry->copyPropertyKeys();
        } else {
                if ((kIORegistryIterateRecursively & options) && plane[0]) {
-                       obj = entry->copyProperty(property_name,
-                           IORegistryEntry::getPlane(plane), options );
+                       if (!IOTaskRegistryCompatibility(current_task())) {
+                               obj = entry->copyProperty(property_name,
+                                   IORegistryEntry::getPlane(plane), options);
+                       } else {
+                               obj = IOCopyPropertyCompatible(entry, property_name);
+                               if ((NULL == obj) && plane && (options & kIORegistryIterateRecursively)) {
+                                       IORegistryIterator * iter;
+                                       iter = IORegistryIterator::iterateOver(entry, IORegistryEntry::getPlane(plane), options);
+                                       if (iter) {
+                                               while ((NULL == obj) && (entry = iter->getNextObject())) {
+                                                       obj = IOCopyPropertyCompatible(entry, property_name);
+                                               }
+                                               iter->release();
+                                       }
+                               }
+                       }
                } else {
-                       obj = entry->copyProperty(property_name);
+                       obj = IOCopyPropertyCompatible(entry, property_name);
                }
                if (obj && gIORemoveOnReadProperties->containsObject(sym)) {
                        entry->removeProperty(sym);
@@ -3515,8 +3966,22 @@ is_io_registry_entry_get_property_bin(
 
        if (obj->serialize( s )) {
                len = s->getLength();
-               *propertiesCnt = len;
-               err = copyoutkdata( s->text(), len, properties );
+               if (buf && bufsize && len <= *bufsize) {
+                       *bufsize = len;
+                       *propertiesCnt = 0;
+                       *properties = nullptr;
+                       if (copyout(s->text(), buf, len)) {
+                               err = kIOReturnVMError;
+                       } else {
+                               err = kIOReturnSuccess;
+                       }
+               } else {
+                       if (bufsize) {
+                               *bufsize = 0;
+                       }
+                       *propertiesCnt = len;
+                       err = copyoutkdata( s->text(), len, properties );
+               }
        } else {
                err = kIOReturnUnsupported;
        }
@@ -3527,6 +3992,20 @@ is_io_registry_entry_get_property_bin(
        return err;
 }
 
+/* Routine io_registry_entry_get_property_bin */
+kern_return_t
+is_io_registry_entry_get_property_bin(
+       io_object_t registry_entry,
+       io_name_t plane,
+       io_name_t property_name,
+       uint32_t options,
+       io_buf_ptr_t *properties,
+       mach_msg_type_number_t *propertiesCnt )
+{
+       return is_io_registry_entry_get_property_bin_buf(registry_entry, plane,
+                  property_name, options, 0, NULL, properties, propertiesCnt);
+}
+
 
 /* Routine io_registry_entry_set_properties */
 kern_return_t
@@ -3717,10 +4196,10 @@ is_io_service_open_extended(
        kern_return_t * result,
        io_object_t *connection )
 {
-       IOUserClient * client = 0;
+       IOUserClient * client = NULL;
        kern_return_t  err = KERN_SUCCESS;
        IOReturn       res = kIOReturnSuccess;
-       OSDictionary * propertiesDict = 0;
+       OSDictionary * propertiesDict = NULL;
        bool           crossEndian;
        bool           disallowAccess;
 
@@ -3791,10 +4270,46 @@ is_io_service_open_extended(
 
                if (res == kIOReturnSuccess) {
                        assert( OSDynamicCast(IOUserClient, client));
+                       if (!client->reserved) {
+                               if (!client->reserve()) {
+                                       client->clientClose();
+                                       OSSafeReleaseNULL(client);
+                                       res = kIOReturnNoMemory;
+                               }
+                       }
+               }
 
-                       client->sharedInstance = (0 != client->getProperty(kIOUserClientSharedInstanceKey));
-                       client->closed = false;
-                       client->lock = IOLockAlloc();
+               if (res == kIOReturnSuccess) {
+                       client->sharedInstance = (NULL != client->getProperty(kIOUserClientSharedInstanceKey));
+                       if (client->sharedInstance) {
+                               IOLockLock(gIOUserClientOwnersLock);
+                       }
+                       if (!client->lock) {
+                               client->lock       = IORWLockAlloc();
+                               client->filterLock = IOLockAlloc();
+
+                               client->messageAppSuspended = (NULL != client->getProperty(kIOUserClientMessageAppSuspendedKey));
+                               {
+                                       OSObject * obj;
+                                       extern const OSSymbol * gIOSurfaceIdentifier;
+                                       obj = client->getProperty(kIOUserClientDefaultLockingKey);
+                                       if (obj) {
+                                               client->defaultLocking = (kOSBooleanFalse != client->getProperty(kIOUserClientDefaultLockingKey));
+                                       } else {
+                                               const OSMetaClass * meta;
+                                               OSKext            * kext;
+                                               meta = client->getMetaClass();
+                                               kext = meta->getKext();
+                                               if (!kext || !kext->hasDependency(gIOSurfaceIdentifier)) {
+                                                       client->defaultLocking = true;
+                                                       client->setProperty(kIOUserClientDefaultLockingKey, kOSBooleanTrue);
+                                               }
+                                       }
+                               }
+                       }
+                       if (client->sharedInstance) {
+                               IOLockUnlock(gIOUserClientOwnersLock);
+                       }
 
                        disallowAccess = (crossEndian
                            && (kOSBooleanTrue != service->getProperty(kIOUserClientCrossEndianCompatibleKey))
@@ -3808,6 +4323,21 @@ is_io_service_open_extended(
                        }
 #endif
 
+                       if ((kIOReturnSuccess == res)
+                           && gIOUCFilterCallbacks
+                           && gIOUCFilterCallbacks->io_filter_resolver) {
+                               io_filter_policy_t filterPolicy;
+                               filterPolicy = client->filterForTask(owningTask, 0);
+                               if (!filterPolicy) {
+                                       res = gIOUCFilterCallbacks->io_filter_resolver(owningTask, client, connect_type, &filterPolicy);
+                                       if (kIOReturnUnsupported == res) {
+                                               res = kIOReturnSuccess;
+                                       } else if (kIOReturnSuccess == res) {
+                                               client->filterForTask(owningTask, filterPolicy);
+                                       }
+                               }
+                       }
+
                        if (kIOReturnSuccess == res) {
                                res = client->registerOwner(owningTask);
                        }
@@ -3816,7 +4346,7 @@ is_io_service_open_extended(
                                IOStatisticsClientCall();
                                client->clientClose();
                                client->release();
-                               client = 0;
+                               client = NULL;
                                break;
                        }
                        OSString * creatorName = IOCopyLogNameForPID(proc_selfpid());
@@ -3849,9 +4379,9 @@ is_io_service_close(
        IOStatisticsClientCall();
 
        if (client->sharedInstance || OSCompareAndSwap8(0, 1, &client->closed)) {
-               IOLockLock(client->lock);
+               IORWLockWrite(client->lock);
                client->clientClose();
-               IOLockUnlock(client->lock);
+               IORWLockUnlock(client->lock);
        } else {
                IOLog("ignored is_io_service_close(0x%qx,%s)\n",
                    client->getRegistryEntryID(), client->getName());
@@ -3892,10 +4422,10 @@ is_io_connect_set_notification_port(
        CHECK( IOUserClient, connection, client );
 
        IOStatisticsClientCall();
-       IOLockLock(client->lock);
+       IORWLockWrite(client->lock);
        ret = client->registerNotificationPort( port, notification_type,
            (io_user_reference_t) reference );
-       IOLockUnlock(client->lock);
+       IORWLockUnlock(client->lock);
        return ret;
 }
 
@@ -3911,10 +4441,10 @@ is_io_connect_set_notification_port_64(
        CHECK( IOUserClient, connection, client );
 
        IOStatisticsClientCall();
-       IOLockLock(client->lock);
+       IORWLockWrite(client->lock);
        ret = client->registerNotificationPort( port, notification_type,
            reference );
-       IOLockUnlock(client->lock);
+       IORWLockUnlock(client->lock);
        return ret;
 }
 
@@ -3940,7 +4470,13 @@ is_io_connect_map_memory_into_task
        }
 
        IOStatisticsClientCall();
+       if (client->defaultLocking) {
+               IORWLockWrite(client->lock);
+       }
        map = client->mapClientMemory64( memory_type, into_task, flags, *address );
+       if (client->defaultLocking) {
+               IORWLockUnlock(client->lock);
+       }
 
        if (map) {
                *address = map->getAddress();
@@ -3959,7 +4495,7 @@ is_io_connect_map_memory_into_task
                } else {
                        // keep it with the user client
                        IOLockLock( gIOObjectPortLock);
-                       if (0 == client->mappings) {
+                       if (NULL == client->mappings) {
                                client->mappings = OSSet::withCapacity(2);
                        }
                        if (client->mappings) {
@@ -4006,7 +4542,7 @@ IOMemoryMap *
 IOUserClient::removeMappingForDescriptor(IOMemoryDescriptor * mem)
 {
        OSIterator *  iter;
-       IOMemoryMap * map = 0;
+       IOMemoryMap * map = NULL;
 
        IOLockLock(gIOObjectPortLock);
 
@@ -4039,7 +4575,7 @@ is_io_connect_unmap_memory_from_task
 {
        IOReturn            err;
        IOOptionBits        options = 0;
-       IOMemoryDescriptor * memory = 0;
+       IOMemoryDescriptor * memory = NULL;
        IOMemoryMap *       map;
 
        CHECK( IOUserClient, connection, client );
@@ -4049,7 +4585,13 @@ is_io_connect_unmap_memory_from_task
        }
 
        IOStatisticsClientCall();
+       if (client->defaultLocking) {
+               IORWLockWrite(client->lock);
+       }
        err = client->clientMemoryForType((UInt32) memory_type, &options, &memory );
+       if (client->defaultLocking) {
+               IORWLockUnlock(client->lock);
+       }
 
        if (memory && (kIOReturnSuccess == err)) {
                options = (options & ~kIOMapUserOptionsMask)
@@ -4065,7 +4607,8 @@ is_io_connect_unmap_memory_from_task
                        IOLockUnlock( gIOObjectPortLock);
 
                        mach_port_name_t name = 0;
-                       if (from_task != current_task()) {
+                       bool is_shared_instance_or_from_current_task = from_task != current_task() || client->sharedInstance;
+                       if (is_shared_instance_or_from_current_task) {
                                name = IOMachPort::makeSendRightForTask( from_task, map, IKOT_IOKIT_OBJECT );
                                map->release();
                        }
@@ -4077,7 +4620,7 @@ is_io_connect_unmap_memory_from_task
                        } else {
                                IOMachPort::releasePortForObject( map, IKOT_IOKIT_OBJECT );
                        }
-                       if (from_task == current_task()) {
+                       if (!is_shared_instance_or_from_current_task) {
                                map->release();
                        }
                } else {
@@ -4115,8 +4658,17 @@ is_io_connect_add_client(
        CHECK( IOUserClient, connection, client );
        CHECK( IOUserClient, connect_to, to );
 
+       IOReturn ret;
+
        IOStatisticsClientCall();
-       return client->connectClient( to );
+       if (client->defaultLocking) {
+               IORWLockWrite(client->lock);
+       }
+       ret = client->connectClient( to );
+       if (client->defaultLocking) {
+               IORWLockUnlock(client->lock);
+       }
+       return ret;
 }
 
 
@@ -4155,8 +4707,8 @@ is_io_connect_method_var_output
 
        IOExternalMethodArguments args;
        IOReturn ret;
-       IOMemoryDescriptor * inputMD  = 0;
-       OSObject *           structureVariableOutputData = 0;
+       IOMemoryDescriptor * inputMD  = NULL;
+       OSObject *           structureVariableOutputData = NULL;
 
        bzero(&args.__reserved[0], sizeof(args.__reserved));
        args.__reservedA = 0;
@@ -4165,7 +4717,7 @@ is_io_connect_method_var_output
        args.selector = selector;
 
        args.asyncWakePort               = MACH_PORT_NULL;
-       args.asyncReference              = 0;
+       args.asyncReference              = NULL;
        args.asyncReferenceCount         = 0;
        args.structureVariableOutputData = &structureVariableOutputData;
 
@@ -4195,7 +4747,21 @@ is_io_connect_method_var_output
        args.structureOutputDescriptorSize = 0;
 
        IOStatisticsClientCall();
-       ret = client->externalMethod( selector, &args );
+       ret = kIOReturnSuccess;
+
+       io_filter_policy_t filterPolicy = client->filterForTask(current_task(), 0);
+       if (filterPolicy && gIOUCFilterCallbacks->io_filter_applier) {
+               ret = gIOUCFilterCallbacks->io_filter_applier(filterPolicy, io_filter_type_external_method, selector);
+       }
+       if (kIOReturnSuccess == ret) {
+               if (client->defaultLocking) {
+                       IORWLockRead(client->lock);
+               }
+               ret = client->externalMethod( selector, &args );
+               if (client->defaultLocking) {
+                       IORWLockUnlock(client->lock);
+               }
+       }
 
        *scalar_outputCnt = args.scalarOutputCount;
        *inband_outputCnt = args.structureOutputSize;
@@ -4203,7 +4769,7 @@ is_io_connect_method_var_output
        if (var_outputCnt && var_output && (kIOReturnSuccess == ret)) {
                OSSerialize * serialize;
                OSData      * data;
-               vm_size_t     len;
+               unsigned int  len;
 
                if ((serialize = OSDynamicCast(OSSerialize, structureVariableOutputData))) {
                        len = serialize->getLength();
@@ -4252,8 +4818,8 @@ is_io_connect_method
 
        IOExternalMethodArguments args;
        IOReturn ret;
-       IOMemoryDescriptor * inputMD  = 0;
-       IOMemoryDescriptor * outputMD = 0;
+       IOMemoryDescriptor * inputMD  = NULL;
+       IOMemoryDescriptor * outputMD = NULL;
 
        bzero(&args.__reserved[0], sizeof(args.__reserved));
        args.__reservedA = 0;
@@ -4262,9 +4828,9 @@ is_io_connect_method
        args.selector = selector;
 
        args.asyncWakePort               = MACH_PORT_NULL;
-       args.asyncReference              = 0;
+       args.asyncReference              = NULL;
        args.asyncReferenceCount         = 0;
-       args.structureVariableOutputData = 0;
+       args.structureVariableOutputData = NULL;
 
        args.scalarInput = scalar_input;
        args.scalarInputCount = scalar_inputCnt;
@@ -4274,8 +4840,13 @@ is_io_connect_method
        if (ool_input && (ool_input_size <= sizeof(io_struct_inband_t))) {
                return kIOReturnIPCError;
        }
-       if (ool_output && (*ool_output_size <= sizeof(io_struct_inband_t))) {
-               return kIOReturnIPCError;
+       if (ool_output) {
+               if (*ool_output_size <= sizeof(io_struct_inband_t)) {
+                       return kIOReturnIPCError;
+               }
+               if (*ool_output_size > UINT_MAX) {
+                       return kIOReturnIPCError;
+               }
        }
 
        if (ool_input) {
@@ -4298,10 +4869,25 @@ is_io_connect_method
        }
 
        args.structureOutputDescriptor = outputMD;
-       args.structureOutputDescriptorSize = ool_output_size ? *ool_output_size : 0;
+       args.structureOutputDescriptorSize = ool_output_size
+           ? ((typeof(args.structureOutputDescriptorSize)) * ool_output_size)
+           : 0;
 
        IOStatisticsClientCall();
-       ret = client->externalMethod( selector, &args );
+       ret = kIOReturnSuccess;
+       io_filter_policy_t filterPolicy = client->filterForTask(current_task(), 0);
+       if (filterPolicy && gIOUCFilterCallbacks->io_filter_applier) {
+               ret = gIOUCFilterCallbacks->io_filter_applier(filterPolicy, io_filter_type_external_method, selector);
+       }
+       if (kIOReturnSuccess == ret) {
+               if (client->defaultLocking) {
+                       IORWLockRead(client->lock);
+               }
+               ret = client->externalMethod( selector, &args );
+               if (client->defaultLocking) {
+                       IORWLockUnlock(client->lock);
+               }
+       }
 
        *scalar_outputCnt = args.scalarOutputCount;
        *inband_outputCnt = args.structureOutputSize;
@@ -4344,8 +4930,12 @@ is_io_connect_async_method
 
        IOExternalMethodArguments args;
        IOReturn ret;
-       IOMemoryDescriptor * inputMD  = 0;
-       IOMemoryDescriptor * outputMD = 0;
+       IOMemoryDescriptor * inputMD  = NULL;
+       IOMemoryDescriptor * outputMD = NULL;
+
+       if (referenceCnt < 1) {
+               return kIOReturnBadArgument;
+       }
 
        bzero(&args.__reserved[0], sizeof(args.__reserved));
        args.__reservedA = 0;
@@ -4362,7 +4952,7 @@ is_io_connect_async_method
        args.asyncReference      = reference;
        args.asyncReferenceCount = referenceCnt;
 
-       args.structureVariableOutputData = 0;
+       args.structureVariableOutputData = NULL;
 
        args.scalarInput = scalar_input;
        args.scalarInputCount = scalar_inputCnt;
@@ -4372,8 +4962,13 @@ is_io_connect_async_method
        if (ool_input && (ool_input_size <= sizeof(io_struct_inband_t))) {
                return kIOReturnIPCError;
        }
-       if (ool_output && (*ool_output_size <= sizeof(io_struct_inband_t))) {
-               return kIOReturnIPCError;
+       if (ool_output) {
+               if (*ool_output_size <= sizeof(io_struct_inband_t)) {
+                       return kIOReturnIPCError;
+               }
+               if (*ool_output_size > UINT_MAX) {
+                       return kIOReturnIPCError;
+               }
        }
 
        if (ool_input) {
@@ -4396,11 +4991,25 @@ is_io_connect_async_method
        }
 
        args.structureOutputDescriptor = outputMD;
-       args.structureOutputDescriptorSize = *ool_output_size;
+       args.structureOutputDescriptorSize = ((typeof(args.structureOutputDescriptorSize)) * ool_output_size);
 
        IOStatisticsClientCall();
-       ret = client->externalMethod( selector, &args );
+       ret = kIOReturnSuccess;
+       io_filter_policy_t filterPolicy = client->filterForTask(current_task(), 0);
+       if (filterPolicy && gIOUCFilterCallbacks->io_filter_applier) {
+               ret = gIOUCFilterCallbacks->io_filter_applier(filterPolicy, io_filter_type_external_async_method, selector);
+       }
+       if (kIOReturnSuccess == ret) {
+               if (client->defaultLocking) {
+                       IORWLockRead(client->lock);
+               }
+               ret = client->externalMethod( selector, &args );
+               if (client->defaultLocking) {
+                       IORWLockUnlock(client->lock);
+               }
+       }
 
+       *scalar_outputCnt = args.scalarOutputCount;
        *inband_outputCnt = args.structureOutputSize;
        *ool_output_size  = args.structureOutputDescriptorSize;
 
@@ -4547,10 +5156,14 @@ is_io_async_method_scalarI_scalarO(
        io_scalar_inband64_t _output;
        io_async_ref64_t _reference;
 
+       if (referenceCnt > ASYNC_REF64_COUNT) {
+               return kIOReturnBadArgument;
+       }
        bzero(&_output[0], sizeof(_output));
        for (i = 0; i < referenceCnt; i++) {
                _reference[i] = REF64(reference[i]);
        }
+       bzero(&_reference[referenceCnt], (ASYNC_REF64_COUNT - referenceCnt) * sizeof(_reference[0]));
 
        mach_msg_type_number_t struct_outputCnt = 0;
        mach_vm_size_t ool_output_size = 0;
@@ -4592,9 +5205,13 @@ is_io_async_method_scalarI_structureO(
        io_scalar_inband64_t _input;
        io_async_ref64_t _reference;
 
+       if (referenceCnt > ASYNC_REF64_COUNT) {
+               return kIOReturnBadArgument;
+       }
        for (i = 0; i < referenceCnt; i++) {
                _reference[i] = REF64(reference[i]);
        }
+       bzero(&_reference[referenceCnt], (ASYNC_REF64_COUNT - referenceCnt) * sizeof(_reference[0]));
 
        mach_msg_type_number_t scalar_outputCnt = 0;
        mach_vm_size_t ool_output_size = 0;
@@ -4631,9 +5248,13 @@ is_io_async_method_scalarI_structureI(
        io_scalar_inband64_t _input;
        io_async_ref64_t _reference;
 
+       if (referenceCnt > ASYNC_REF64_COUNT) {
+               return kIOReturnBadArgument;
+       }
        for (i = 0; i < referenceCnt; i++) {
                _reference[i] = REF64(reference[i]);
        }
+       bzero(&_reference[referenceCnt], (ASYNC_REF64_COUNT - referenceCnt) * sizeof(_reference[0]));
 
        mach_msg_type_number_t scalar_outputCnt = 0;
        mach_msg_type_number_t inband_outputCnt = 0;
@@ -4672,9 +5293,13 @@ is_io_async_method_structureI_structureO(
        mach_vm_size_t ool_output_size = 0;
        io_async_ref64_t _reference;
 
+       if (referenceCnt > ASYNC_REF64_COUNT) {
+               return kIOReturnBadArgument;
+       }
        for (i = 0; i < referenceCnt; i++) {
                _reference[i] = REF64(reference[i]);
        }
+       bzero(&_reference[referenceCnt], (ASYNC_REF64_COUNT - referenceCnt) * sizeof(_reference[0]));
 
        return is_io_connect_async_method(connect,
                   wake_port, _reference, referenceCnt,
@@ -4853,18 +5478,18 @@ shim_io_connect_method_scalarI_structureO(
                        break;
                case 3:
                        err = (object->*func)(  ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
-                           output, (void *)outputCount, 0 );
+                           output, (void *)outputCount, NULL );
                        break;
                case 2:
                        err = (object->*func)(  ARG32(input[0]), ARG32(input[1]),
-                           output, (void *)outputCount, 0, 0 );
+                           output, (void *)outputCount, NULL, NULL );
                        break;
                case 1:
                        err = (object->*func)(  ARG32(input[0]),
-                           output, (void *)outputCount, 0, 0, 0 );
+                           output, (void *)outputCount, NULL, NULL, NULL );
                        break;
                case 0:
-                       err = (object->*func)(  output, (void *)outputCount, 0, 0, 0, 0 );
+                       err = (object->*func)(  output, (void *)outputCount, NULL, NULL, NULL, NULL );
                        break;
 
                default:
@@ -4929,21 +5554,21 @@ shim_io_async_method_scalarI_structureO(
                case 3:
                        err = (object->*func)(  reference,
                            ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
-                           output, (void *)outputCount, 0 );
+                           output, (void *)outputCount, NULL );
                        break;
                case 2:
                        err = (object->*func)(  reference,
                            ARG32(input[0]), ARG32(input[1]),
-                           output, (void *)outputCount, 0, 0 );
+                           output, (void *)outputCount, NULL, NULL );
                        break;
                case 1:
                        err = (object->*func)(  reference,
                            ARG32(input[0]),
-                           output, (void *)outputCount, 0, 0, 0 );
+                           output, (void *)outputCount, NULL, NULL, NULL );
                        break;
                case 0:
                        err = (object->*func)(  reference,
-                           output, (void *)outputCount, 0, 0, 0, 0 );
+                           output, (void *)outputCount, NULL, NULL, NULL, NULL );
                        break;
 
                default:
@@ -5025,21 +5650,21 @@ shim_io_connect_method_scalarI_structureI(
                case 3:
                        err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
                            inputStruct, (void *)(uintptr_t)inputStructCount,
-                           0 );
+                           NULL );
                        break;
                case 2:
                        err = (object->*func)( ARG32(input[0]), ARG32(input[1]),
                            inputStruct, (void *)(uintptr_t)inputStructCount,
-                           0, 0 );
+                           NULL, NULL );
                        break;
                case 1:
                        err = (object->*func)( ARG32(input[0]),
                            inputStruct, (void *)(uintptr_t)inputStructCount,
-                           0, 0, 0 );
+                           NULL, NULL, NULL );
                        break;
                case 0:
                        err = (object->*func)( inputStruct, (void *)(uintptr_t)inputStructCount,
-                           0, 0, 0, 0 );
+                           NULL, NULL, NULL, NULL );
                        break;
 
                default:
@@ -5103,24 +5728,24 @@ shim_io_async_method_scalarI_structureI(
                        err = (object->*func)(  reference,
                            ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
                            inputStruct, (void *)(uintptr_t)inputStructCount,
-                           0 );
+                           NULL );
                        break;
                case 2:
                        err = (object->*func)(  reference,
                            ARG32(input[0]), ARG32(input[1]),
                            inputStruct, (void *)(uintptr_t)inputStructCount,
-                           0, 0 );
+                           NULL, NULL );
                        break;
                case 1:
                        err = (object->*func)(  reference,
                            ARG32(input[0]),
                            inputStruct, (void *)(uintptr_t)inputStructCount,
-                           0, 0, 0 );
+                           NULL, NULL, NULL );
                        break;
                case 0:
                        err = (object->*func)(  reference,
                            inputStruct, (void *)(uintptr_t)inputStructCount,
-                           0, 0, 0, 0 );
+                           NULL, NULL, NULL, NULL );
                        break;
 
                default:
@@ -5184,12 +5809,12 @@ shim_io_connect_method_structureI_structureO(
                if (method->count1) {
                        if (method->count0) {
                                err = (object->*func)( input, output,
-                                   (void *)(uintptr_t)inputCount, outputCount, 0, 0 );
+                                   (void *)(uintptr_t)inputCount, outputCount, NULL, NULL );
                        } else {
-                               err = (object->*func)( output, outputCount, 0, 0, 0, 0 );
+                               err = (object->*func)( output, outputCount, NULL, NULL, NULL, NULL );
                        }
                } else {
-                       err = (object->*func)( input, (void *)(uintptr_t)inputCount, 0, 0, 0, 0 );
+                       err = (object->*func)( input, (void *)(uintptr_t)inputCount, NULL, NULL, NULL, NULL );
                }
        }while (false);
 
@@ -5239,24 +5864,20 @@ shim_io_async_method_structureI_structureO(
                        if (method->count0) {
                                err = (object->*func)( reference,
                                    input, output,
-                                   (void *)(uintptr_t)inputCount, outputCount, 0, 0 );
+                                   (void *)(uintptr_t)inputCount, outputCount, NULL, NULL );
                        } else {
                                err = (object->*func)( reference,
-                                   output, outputCount, 0, 0, 0, 0 );
+                                   output, outputCount, NULL, NULL, NULL, NULL );
                        }
                } else {
                        err = (object->*func)( reference,
-                           input, (void *)(uintptr_t)inputCount, 0, 0, 0, 0 );
+                           input, (void *)(uintptr_t)inputCount, NULL, NULL, NULL, NULL );
                }
        }while (false);
 
        return err;
 }
 
-#if !NO_KEXTD
-bool gIOKextdClearedBusy = false;
-#endif
-
 /* Routine io_catalog_send_data */
 kern_return_t
 is_io_catalog_send_data(
@@ -5269,7 +5890,7 @@ is_io_catalog_send_data(
 #if NO_KEXTD
        return kIOReturnNotPrivileged;
 #else /* NO_KEXTD */
-       OSObject * obj = 0;
+       OSObject * obj = NULL;
        vm_offset_t data;
        kern_return_t kr = kIOReturnError;
 
@@ -5279,14 +5900,14 @@ is_io_catalog_send_data(
                return kIOReturnNotPrivileged;
        }
 
-       if ((flag != kIOCatalogRemoveKernelLinker &&
+       if ((flag != kIOCatalogRemoveKernelLinker__Removed &&
            flag != kIOCatalogKextdActive &&
            flag != kIOCatalogKextdFinishedLaunching) &&
            (!inData || !inDataCount)) {
                return kIOReturnBadArgument;
        }
 
-       if (!IOTaskHasEntitlement(current_task(), "com.apple.rootless.kext-secure-management")) {
+       if (!IOTaskHasEntitlement(current_task(), kIOCatalogManagementEntitlement)) {
                OSString * taskName = IOCopyLogNameForPID(proc_selfpid());
                IOLog("IOCatalogueSendData(%s): Not entitled\n", taskName ? taskName->getCStringNoCopy() : "");
                OSSafeReleaseNULL(taskName);
@@ -5370,52 +5991,13 @@ is_io_catalog_send_data(
        }
        break;
 
-       case kIOCatalogStartMatching: {
-               OSDictionary * dict;
-
-               dict = OSDynamicCast(OSDictionary, obj);
-               if (dict) {
-                       if (!gIOCatalogue->startMatching( dict )) {
-                               kr = kIOReturnError;
-                       }
-               } else {
-                       kr = kIOReturnBadArgument;
-               }
-       }
-       break;
-
-       case kIOCatalogRemoveKernelLinker:
-               kr = KERN_NOT_SUPPORTED;
-               break;
-
+       case kIOCatalogStartMatching__Removed:
+       case kIOCatalogRemoveKernelLinker__Removed:
        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
-                * down on request.
-                */
-               OSKext::flushNonloadedKexts( /* flushPrelinkedKexts */ false);
-#endif
-               kr = kIOReturnSuccess;
+       case kIOCatalogKextdFinishedLaunching:
+               kr = KERN_NOT_SUPPORTED;
                break;
 
-       case kIOCatalogKextdFinishedLaunching: {
-#if !NO_KEXTD
-               if (!gIOKextdClearedBusy) {
-                       IOService * serviceRoot = IOService::getServiceRoot();
-                       if (serviceRoot) {
-                               IOServiceTrace(IOSERVICE_KEXTD_READY, 0, 0, 0, 0);
-                               serviceRoot->adjustBusy(-1);
-                               gIOKextdClearedBusy = true;
-                       }
-               }
-#endif
-               kr = kIOReturnSuccess;
-       }
-       break;
-
        default:
                kr = kIOReturnBadArgument;
                break;
@@ -5452,28 +6034,7 @@ is_io_catalog_terminate(
        switch (flag) {
 #if !defined(SECURE_KERNEL)
        case kIOCatalogServiceTerminate:
-               OSIterator *        iter;
-               IOService *         service;
-
-               iter = IORegistryIterator::iterateOver(gIOServicePlane,
-                   kIORegistryIterateRecursively);
-               if (!iter) {
-                       return kIOReturnNoMemory;
-               }
-
-               do {
-                       iter->reset();
-                       while ((service = (IOService *)iter->getNextObject())) {
-                               if (service->metaCast(name)) {
-                                       if (!service->terminate( kIOServiceRequired
-                                           | kIOServiceSynchronous)) {
-                                               kr = kIOReturnUnsupported;
-                                               break;
-                                       }
-                               }
-                       }
-               } while (!service && !iter->isValid());
-               iter->release();
+               kr = gIOCatalogue->terminateDrivers(NULL, name);
                break;
 
        case kIOCatalogModuleUnload:
@@ -5518,14 +6079,14 @@ is_io_catalog_get_data(
        if (kr == kIOReturnSuccess) {
                vm_offset_t data;
                vm_map_copy_t copy;
-               vm_size_t size;
+               unsigned int size;
 
                size = s->getLength();
                kr = vm_allocate_kernel(kernel_map, &data, size, VM_FLAGS_ANYWHERE, VM_KERN_MEMORY_IOKIT);
                if (kr == kIOReturnSuccess) {
                        bcopy(s->text(), (void *)data, size);
                        kr = vm_map_copyin(kernel_map, (vm_map_address_t)data,
-                           (vm_map_size_t)size, true, &copy);
+                           size, true, &copy);
                        *outData = (char *)copy;
                        *outDataCount = size;
                }
@@ -5604,16 +6165,30 @@ is_io_catalog_reset(
 kern_return_t
 iokit_user_client_trap(struct iokit_user_client_trap_args *args)
 {
-       kern_return_t result = kIOReturnBadArgument;
-       IOUserClient *userClient;
+       kern_return_t  result = kIOReturnBadArgument;
+       IOUserClient * userClient;
+       OSObject     * object;
+       uintptr_t      ref;
 
-       if ((userClient = OSDynamicCast(IOUserClient,
-           iokit_lookup_connect_ref_current_task((mach_port_name_t)(uintptr_t)args->userClientRef)))) {
-               IOExternalTrap *trap;
+       ref = (uintptr_t) args->userClientRef;
+       if ((1ULL << 32) & ref) {
+               object = iokit_lookup_uext_ref_current_task((mach_port_name_t) ref);
+               if (object) {
+                       result = IOUserServerUEXTTrap(object, args->p1, args->p2, args->p3, args->p4, args->p5, args->p6);
+               }
+               OSSafeReleaseNULL(object);
+       } else if ((userClient = OSDynamicCast(IOUserClient, iokit_lookup_connect_ref_current_task((mach_port_name_t) ref)))) {
+               IOExternalTrap *trap = NULL;
                IOService *target = NULL;
 
-               trap = userClient->getTargetAndTrapForIndex(&target, args->index);
-
+               result = kIOReturnSuccess;
+               io_filter_policy_t filterPolicy = userClient->filterForTask(current_task(), 0);
+               if (filterPolicy && gIOUCFilterCallbacks->io_filter_applier) {
+                       result = gIOUCFilterCallbacks->io_filter_applier(filterPolicy, io_filter_type_trap, args->index);
+               }
+               if (kIOReturnSuccess == result) {
+                       trap = userClient->getTargetAndTrapForIndex(&target, args->index);
+               }
                if (trap && target) {
                        IOTrap func;
 
@@ -5704,7 +6279,7 @@ IOUserClient::externalMethod( uint32_t selector, IOExternalMethodArguments * arg
 
        if (args->asyncWakePort) {
                IOExternalAsyncMethod * method;
-               object = 0;
+               object = NULL;
                if (!(method = getAsyncTargetAndMethodForIndex(&object, selector)) || !object) {
                        return kIOReturnUnsupported;
                }
@@ -5751,7 +6326,7 @@ IOUserClient::externalMethod( uint32_t selector, IOExternalMethodArguments * arg
                }
        } else {
                IOExternalMethod *      method;
-               object = 0;
+               object = NULL;
                if (!(method = getTargetAndMethodForIndex(&object, selector)) || !object) {
                        return kIOReturnUnsupported;
                }
@@ -5794,11 +6369,28 @@ IOUserClient::externalMethod( uint32_t selector, IOExternalMethodArguments * arg
                }
        }
 
-       args->structureOutputSize = structureOutputSize;
+       if (structureOutputSize > UINT_MAX) {
+               structureOutputSize = 0;
+               err = kIOReturnBadArgument;
+       }
+
+       args->structureOutputSize = ((typeof(args->structureOutputSize))structureOutputSize);
 
        return err;
 }
 
+IOReturn
+IOUserClient::registerFilterCallbacks(const struct io_filter_callbacks *callbacks, size_t size)
+{
+       if (size < sizeof(*callbacks)) {
+               return kIOReturnBadArgument;
+       }
+       if (!OSCompareAndSwapPtr(NULL, __DECONST(void *, callbacks), &gIOUCFilterCallbacks)) {
+               return kIOReturnBusy;
+       }
+       return kIOReturnSuccess;
+}
+
 #if __LP64__
 OSMetaClassDefineReservedUnused(IOUserClient, 0);
 OSMetaClassDefineReservedUnused(IOUserClient, 1);