#include <IOKit/IOBSD.h>
#include <IOKit/IOStatisticsPrivate.h>
#include <IOKit/IOTimeStamp.h>
+#include <IOKit/IODeviceTreeSupport.h>
#include <IOKit/system.h>
#include <libkern/OSDebug.h>
#include <sys/proc.h>
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-// definitions we should get from osfmk
-
-//typedef struct ipc_port * ipc_port_t;
-typedef natural_t ipc_kobject_type_t;
-
-#define IKOT_IOKIT_SPARE 27
-#define IKOT_IOKIT_CONNECT 29
-#define IKOT_IOKIT_OBJECT 30
-
extern "C" {
-extern ipc_port_t iokit_alloc_object_port( io_object_t obj,
- ipc_kobject_type_t type );
-
-extern kern_return_t iokit_destroy_object_port( ipc_port_t port );
-
-extern mach_port_name_t iokit_make_send_right( task_t task,
- io_object_t obj, ipc_kobject_type_t type );
-
-extern kern_return_t iokit_mod_send_right( task_t task, mach_port_name_t name, mach_port_delta_t delta );
-
-extern io_object_t iokit_lookup_connect_ref(io_object_t clientRef, ipc_space_t task);
-
-extern io_object_t iokit_lookup_connect_ref_current_task(io_object_t clientRef);
-
-extern ipc_port_t master_device_port;
-
-extern void iokit_retain_port( ipc_port_t port );
-extern void iokit_release_port( ipc_port_t port );
-extern void iokit_release_port_send( ipc_port_t port );
-
-extern kern_return_t iokit_switch_object_port( ipc_port_t port, io_object_t obj, ipc_kobject_type_t type );
-
#include <mach/mach_traps.h>
#include <vm/vm_map.h>
} /* extern "C" */
-
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// IOMachPort maps OSObjects to ports, avoiding adding an ivar to OSObject.
// not in dictForType() for debugging ease
static OSDictionary * gIOObjectPorts;
static OSDictionary * gIOConnectPorts;
+static OSDictionary * gIOIdentifierPorts;
OSDictionary * IOMachPort::dictForType( ipc_kobject_type_t type )
{
OSDictionary ** dict;
- if( IKOT_IOKIT_OBJECT == type )
- dict = &gIOObjectPorts;
- else if( IKOT_IOKIT_CONNECT == type )
- dict = &gIOConnectPorts;
- else
- return( 0 );
+ switch (type)
+ {
+ case IKOT_IOKIT_OBJECT:
+ dict = &gIOObjectPorts;
+ break;
+ case IKOT_IOKIT_CONNECT:
+ dict = &gIOConnectPorts;
+ break;
+ case IKOT_IOKIT_IDENT:
+ dict = &gIOIdentifierPorts;
+ break;
+ default:
+ panic("dictForType %d", type);
+ dict = NULL;
+ break;
+ }
if( 0 == *dict)
*dict = OSDictionary::withCapacity( 1 );
virtual void reset() APPLE_KEXT_OVERRIDE;
virtual bool isValid() APPLE_KEXT_OVERRIDE;
virtual OSObject * getNextObject() APPLE_KEXT_OVERRIDE;
+ virtual OSObject * copyNextObject();
};
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
OSObject *
IOUserIterator::getNextObject()
{
- OSObject * ret;
+ assert(false);
+ return (NULL);
+}
+
+OSObject *
+IOUserIterator::copyNextObject()
+{
+ OSObject * ret = NULL;
IOLockLock(lock);
- assert(OSDynamicCast(OSIterator, userIteratorObject));
- ret = ((OSIterator *)userIteratorObject)->getNextObject();
+ if (userIteratorObject) {
+ ret = ((OSIterator *)userIteratorObject)->getNextObject();
+ if (ret) ret->retain();
+ }
IOLockUnlock(lock);
return (ret);
// functions called from osfmk/device/iokit_rpc.c
void
-iokit_add_reference( io_object_t obj )
+iokit_add_reference( io_object_t obj, ipc_kobject_type_t type )
{
- if( obj)
- obj->retain();
+ IOUserClient * uc;
+
+ if (!obj) return;
+
+ if ((IKOT_IOKIT_CONNECT == type)
+ && (uc = OSDynamicCast(IOUserClient, obj)))
+ {
+ OSIncrementAtomic(&uc->__ipc);
+ }
+
+ obj->retain();
}
void
obj->release();
}
-void
-iokit_add_connect_reference( io_object_t obj )
-{
- IOUserClient * uc;
-
- if (!obj) return;
-
- if ((uc = OSDynamicCast(IOUserClient, obj))) OSIncrementAtomic(&uc->__ipc);
-
- obj->retain();
-}
-
void
iokit_remove_connect_reference( io_object_t obj )
{
if( (client = OSDynamicCast( IOUserClient, obj )))
{
IOStatisticsClientCall();
+ IOLockLock(client->lock);
client->clientDied();
+ IOLockUnlock(client->lock);
}
}
else if( IKOT_IOKIT_OBJECT == type)
PingMsg * pingMsg;
vm_size_t msgSize;
OSArray * newSet;
- OSObject * lastEntry;
bool armed;
bool ipcLogged;
void * reference, vm_size_t referenceSize,
bool clientIs64 );
virtual void free() APPLE_KEXT_OVERRIDE;
+ void invalidatePort(void);
static bool _handler( void * target,
void * ref, IOService * newService, IONotifier * notifier );
virtual bool handler( void * ref, IOService * newService );
virtual OSObject * getNextObject() APPLE_KEXT_OVERRIDE;
+ virtual OSObject * copyNextObject() APPLE_KEXT_OVERRIDE;
};
class IOServiceMessageUserNotification : public IOUserNotification
bool clientIs64 );
virtual void free() APPLE_KEXT_OVERRIDE;
+ void invalidatePort(void);
static IOReturn _handler( void * target, void * ref,
UInt32 messageType, IOService * provider,
void * messageArgument, vm_size_t argSize );
virtual OSObject * getNextObject() APPLE_KEXT_OVERRIDE;
+ virtual OSObject * copyNextObject() APPLE_KEXT_OVERRIDE;
};
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
return( true );
}
+void IOServiceUserNotification::invalidatePort(void)
+{
+ if (pingMsg) pingMsg->msgHdr.msgh_remote_port = MACH_PORT_NULL;
+}
+
void IOServiceUserNotification::free( void )
{
PingMsg * _pingMsg;
vm_size_t _msgSize;
OSArray * _newSet;
- OSObject * _lastEntry;
_pingMsg = pingMsg;
_msgSize = msgSize;
- _lastEntry = lastEntry;
_newSet = newSet;
super::free();
IOFree(_pingMsg, _msgSize);
}
- if( _lastEntry)
- _lastEntry->release();
-
if( _newSet)
_newSet->release();
}
return( true );
}
-
OSObject * IOServiceUserNotification::getNextObject()
+{
+ assert(false);
+ return (NULL);
+}
+
+OSObject * IOServiceUserNotification::copyNextObject()
{
unsigned int count;
OSObject * result;
- OSObject * releaseEntry;
IOLockLock(lock);
- releaseEntry = lastEntry;
count = newSet->getCount();
if( count ) {
result = newSet->getObject( count - 1 );
result = 0;
armed = true;
}
- lastEntry = result;
IOLockUnlock(lock);
- if (releaseEntry) releaseEntry->release();
-
return( result );
}
return( true );
}
+void IOServiceMessageUserNotification::invalidatePort(void)
+{
+ if (pingMsg) pingMsg->msgHdr.msgh_remote_port = MACH_PORT_NULL;
+}
+
void IOServiceMessageUserNotification::free( void )
{
PingMsg * _pingMsg;
}
else
{
+ if( callerArgSize > kIOUserNotifyMaxMessageSize)
+ callerArgSize = kIOUserNotifyMaxMessageSize;
argSize = callerArgSize;
- if( argSize > kIOUserNotifyMaxMessageSize)
- argSize = kIOUserNotifyMaxMessageSize;
}
// adjust message size for ipc restrictions
return( 0 );
}
+OSObject * IOServiceMessageUserNotification::copyNextObject()
+{
+ return( NULL );
+}
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#undef super
if (newOwner)
{
owner = IONew(IOUserClientOwner, 1);
- if (!newOwner) ret = kIOReturnNoMemory;
+ if (!owner) ret = kIOReturnNoMemory;
else
{
owner->task = task;
void IOUserClient::free()
{
if( mappings) mappings->release();
+ if (lock) IOLockFree(lock);
IOStatisticsUnregisterCounter();
name = IOMachPort::makeSendRightForTask( task, obj, IKOT_IOKIT_OBJECT );
*(mach_port_name_t *)clientObj = name;
+
+ if (obj) obj->release();
+
return kIOReturnSuccess;
}
+IOReturn IOUserClient::copyPortNameForObjectInTask(task_t task,
+ OSObject *obj, mach_port_name_t * port_name)
+{
+ mach_port_name_t name;
+
+ name = IOMachPort::makeSendRightForTask( task, obj, IKOT_IOKIT_IDENT );
+
+ *(mach_port_name_t *) port_name = name;
+
+ return kIOReturnSuccess;
+}
+
+IOReturn IOUserClient::copyObjectForPortNameInTask(task_t task, mach_port_name_t port_name,
+ OSObject **obj)
+{
+ OSObject * object;
+
+ object = iokit_lookup_object_with_port_name(port_name, IKOT_IOKIT_IDENT, task);
+
+ *obj = object;
+
+ return (object ? kIOReturnSuccess : kIOReturnIPCError);
+}
+
+IOReturn IOUserClient::adjustPortNameReferencesInTask(task_t task, mach_port_name_t port_name, mach_port_delta_t delta)
+{
+ return (iokit_mod_send_right(task, port_name, delta));
+}
+
IOExternalMethod * IOUserClient::getExternalMethodForIndex( UInt32 /* index */)
{
return( 0 );
io_name_t obj_name,
io_name_t class_name)
{
- const OSMetaClass* my_obj = NULL;
- const OSMetaClass* superclass = NULL;
- const OSSymbol *my_name = NULL;
- const char *my_cstr = NULL;
+ IOReturn ret;
+ const OSMetaClass * meta;
+ const OSMetaClass * super;
+ const OSSymbol * name;
+ const char * cstr;
- if (!obj_name || !class_name)
- return (kIOReturnBadArgument);
+ if (!obj_name || !class_name) return (kIOReturnBadArgument);
+ if (master_port != master_device_port) return( kIOReturnNotPrivileged);
- if( master_port != master_device_port)
- return( kIOReturnNotPrivileged);
+ ret = kIOReturnNotFound;
+ meta = 0;
+ do
+ {
+ name = OSSymbol::withCString(obj_name);
+ if (!name) break;
+ meta = OSMetaClass::copyMetaClassWithName(name);
+ if (!meta) break;
+ super = meta->getSuperClass();
+ if (!super) break;
+ cstr = super->getClassName();
+ if (!cstr) break;
+ strlcpy(class_name, cstr, sizeof(io_name_t));
+ ret = kIOReturnSuccess;
+ }
+ while (false);
- my_name = OSSymbol::withCString(obj_name);
-
- if (my_name) {
- my_obj = OSMetaClass::getMetaClassWithName(my_name);
- my_name->release();
- }
- if (my_obj) {
- superclass = my_obj->getSuperClass();
- }
-
- if (!superclass) {
- return( kIOReturnNotFound );
- }
+ OSSafeReleaseNULL(name);
+ if (meta) meta->releaseMetaClass();
- my_cstr = superclass->getClassName();
-
- if (my_cstr) {
- strlcpy(class_name, my_cstr, sizeof(io_name_t));
- return( kIOReturnSuccess );
- }
- return (kIOReturnNotFound);
+ return (ret);
}
/* Routine io_object_get_bundle_identifier */
io_name_t obj_name,
io_name_t bundle_name)
{
- const OSMetaClass* my_obj = NULL;
- const OSSymbol *my_name = NULL;
- const OSSymbol *identifier = NULL;
- const char *my_cstr = NULL;
+ IOReturn ret;
+ const OSMetaClass * meta;
+ const OSSymbol * name;
+ const OSSymbol * identifier;
+ const char * cstr;
- if (!obj_name || !bundle_name)
- return (kIOReturnBadArgument);
+ if (!obj_name || !bundle_name) return (kIOReturnBadArgument);
+ if (master_port != master_device_port) return( kIOReturnNotPrivileged);
- if( master_port != master_device_port)
- return( kIOReturnNotPrivileged);
-
- my_name = OSSymbol::withCString(obj_name);
-
- if (my_name) {
- my_obj = OSMetaClass::getMetaClassWithName(my_name);
- my_name->release();
- }
+ ret = kIOReturnNotFound;
+ meta = 0;
+ do
+ {
+ name = OSSymbol::withCString(obj_name);
+ if (!name) break;
+ meta = OSMetaClass::copyMetaClassWithName(name);
+ if (!meta) break;
+ identifier = meta->getKmodName();
+ if (!identifier) break;
+ cstr = identifier->getCStringNoCopy();
+ if (!cstr) break;
+ strlcpy(bundle_name, identifier->getCStringNoCopy(), sizeof(io_name_t));
+ ret = kIOReturnSuccess;
+ }
+ while (false);
- if (my_obj) {
- identifier = my_obj->getKmodName();
- }
- if (!identifier) {
- return( kIOReturnNotFound );
- }
-
- my_cstr = identifier->getCStringNoCopy();
- if (my_cstr) {
- strlcpy(bundle_name, identifier->getCStringNoCopy(), sizeof(io_name_t));
- return( kIOReturnSuccess );
- }
+ OSSafeReleaseNULL(name);
+ if (meta) meta->releaseMetaClass();
- return (kIOReturnBadArgument);
+ return (ret);
}
/* Routine io_object_conforms_to */
{
IOReturn ret;
OSObject * obj;
+ OSIterator * iter;
+ IOUserIterator * uiter;
- CHECK( OSIterator, iterator, iter );
+ if ((uiter = OSDynamicCast(IOUserIterator, iterator)))
+ {
+ obj = uiter->copyNextObject();
+ }
+ else if ((iter = OSDynamicCast(OSIterator, iterator)))
+ {
+ obj = iter->getNextObject();
+ if (obj) obj->retain();
+ }
+ else
+ {
+ return( kIOReturnBadArgument );
+ }
- obj = iter->getNextObject();
if( obj) {
- obj->retain();
*object = obj;
ret = kIOReturnSuccess;
} else
do {
err = kIOReturnNoResources;
+ if (matching_size > (sizeof(io_struct_inband_t) * 1024)) return(kIOReturnMessageTooLarge);
+
if( !(sym = OSSymbol::withCString( notification_type )))
err = kIOReturnNoResources;
else if( (sym == gIOMatchedNotification)
|| (sym == gIOFirstMatchNotification))
userMsgType = kIOServiceMatchedNotificationType;
- else if( sym == gIOTerminatedNotification)
+ else if ((sym == gIOTerminatedNotification)
+ || (sym == gIOWillTerminateNotification))
userMsgType = kIOServiceTerminatedNotificationType;
else
userMsgType = kLastIOKitNotificationType;
if( userNotify && !userNotify->init( port, userMsgType,
reference, referenceSize, client64)) {
- iokit_release_port_send(port);
userNotify->release();
userNotify = 0;
}
} while( false );
+ if ((kIOReturnSuccess != err) && userNotify)
+ {
+ userNotify->invalidatePort();
+ userNotify->release();
+ userNotify = 0;
+ }
+
if( sym)
sym->release();
if( dict)
reference, referenceSize,
kIOUserNotifyMaxMessageSize,
client64 )) {
- iokit_release_port_send(port);
userNotify->release();
userNotify = 0;
}
} while( false );
+ if ((kIOReturnSuccess != err) && userNotify)
+ {
+ userNotify->invalidatePort();
+ userNotify->release();
+ userNotify = 0;
+ }
+
return( err );
}
{
CHECK( IORegistryEntry, registry_entry, entry );
- *iterator = entry->getChildIterator(
- IORegistryEntry::getPlane( plane ));
+ *iterator = IOUserIterator::withIterator(entry->getChildIterator(
+ IORegistryEntry::getPlane( plane )));
return( kIOReturnSuccess );
}
{
CHECK( IORegistryEntry, registry_entry, entry );
- *iterator = entry->getParentIterator(
- IORegistryEntry::getPlane( plane ));
+ *iterator = IOUserIterator::withIterator(entry->getParentIterator(
+ IORegistryEntry::getPlane( plane )));
return( kIOReturnSuccess );
}
client->sharedInstance = (0 != client->getProperty(kIOUserClientSharedInstanceKey));
client->closed = false;
+ client->lock = IOLockAlloc();
disallowAccess = (crossEndian
&& (kOSBooleanTrue != service->getProperty(kIOUserClientCrossEndianCompatibleKey))
if (client->sharedInstance || OSCompareAndSwap8(0, 1, &client->closed))
{
+ IOLockLock(client->lock);
client->clientClose();
+ IOLockUnlock(client->lock);
}
else
{
mach_port_t port,
uint32_t reference)
{
+ kern_return_t ret;
CHECK( IOUserClient, connection, client );
IOStatisticsClientCall();
- return( client->registerNotificationPort( port, notification_type,
- (io_user_reference_t) reference ));
+ IOLockLock(client->lock);
+ ret = client->registerNotificationPort( port, notification_type,
+ (io_user_reference_t) reference );
+ IOLockUnlock(client->lock);
+ return (ret);
}
/* Routine io_connect_set_notification_port */
mach_port_t port,
io_user_reference_t reference)
{
+ kern_return_t ret;
CHECK( IOUserClient, connection, client );
IOStatisticsClientCall();
- return( client->registerNotificationPort( port, notification_type,
- reference ));
+ IOLockLock(client->lock);
+ ret = client->registerNotificationPort( port, notification_type,
+ reference );
+ IOLockUnlock(client->lock);
+ return (ret);
}
/* Routine io_connect_map_memory_into_task */
mach_port_name_t name __unused =
IOMachPort::makeSendRightForTask(
into_task, map, IKOT_IOKIT_OBJECT );
+ map->release();
} else {
// keep it with the user client
mach_port_name_t name = 0;
if (from_task != current_task())
+ {
name = IOMachPort::makeSendRightForTask( from_task, map, IKOT_IOKIT_OBJECT );
+ map->release();
+ }
+
if (name)
{
map->userClientUnmap();
args.asyncReference = reference;
args.asyncReferenceCount = referenceCnt;
+ args.structureVariableOutputData = 0;
+
args.scalarInput = scalar_input;
args.scalarInputCount = scalar_inputCnt;
args.structureInput = inband_input;
return kIOReturnBadArgument;
}
- if (!IOTaskHasEntitlement(current_task(), "com.apple.rootless.kext-management"))
+ if (!IOTaskHasEntitlement(current_task(), "com.apple.rootless.kext-secure-management"))
{
OSString * taskName = IOCopyLogNameForPID(proc_selfpid());
IOLog("IOCatalogueSendData(%s): Not entitled\n", taskName ? taskName->getCStringNoCopy() : "");
vm_size_t size;
size = s->getLength();
- kr = vm_allocate(kernel_map, &data, size, VM_FLAGS_ANYWHERE);
+ 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,
IOUserClient *userClient;
if ((userClient = OSDynamicCast(IOUserClient,
- iokit_lookup_connect_ref_current_task((OSObject *)(args->userClientRef))))) {
+ iokit_lookup_connect_ref_current_task((mach_port_name_t)(uintptr_t)args->userClientRef)))) {
IOExternalTrap *trap;
IOService *target = NULL;
return result;
}
+/* Routine io_device_tree_entry_exists_with_name */
+kern_return_t is_io_device_tree_entry_exists_with_name(
+ mach_port_t master_port,
+ io_name_t name,
+ boolean_t *exists )
+{
+ OSCollectionIterator *iter;
+
+ if (master_port != master_device_port)
+ return (kIOReturnNotPrivileged);
+
+ iter = IODTFindMatchingEntries(IORegistryEntry::getRegistryRoot(), kIODTRecursive, name);
+ *exists = iter && iter->getNextObject();
+ OSSafeReleaseNULL(iter);
+
+ return kIOReturnSuccess;
+}
+
} /* extern "C" */
IOReturn IOUserClient::externalMethod( uint32_t selector, IOExternalMethodArguments * args,