X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/1c79356b52d46aa6b508fb032f5ae709b1f2897b..743b15655a24ee3fe9f458f383003e011db0558f:/iokit/Kernel/IOUserClient.cpp diff --git a/iokit/Kernel/IOUserClient.cpp b/iokit/Kernel/IOUserClient.cpp index 83e846bca..4a3df066f 100644 --- a/iokit/Kernel/IOUserClient.cpp +++ b/iokit/Kernel/IOUserClient.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1998-2004 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -19,18 +19,12 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* - * Copyright (c) 1998 Apple Computer, Inc. All rights reserved. - * - * HISTORY - * - * 14 Aug 98 sdouglas created. - * 08 Dec 98 sdouglas cpp. - */ + #include #include #include +#include #include #include #include @@ -38,6 +32,8 @@ #include +#include "IOServicePrivate.h" + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // definitions we should get from osfmk @@ -59,12 +55,20 @@ 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 kern_return_t iokit_switch_object_port( ipc_port_t port, io_object_t obj, ipc_kobject_type_t type ); + +#include #include } /* extern "C" */ @@ -80,11 +84,17 @@ class IOMachPort : public OSObject public: OSObject * object; ipc_port_t port; + UInt32 mscount; + UInt8 holdDestroy; 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, @@ -136,8 +146,11 @@ IOMachPort * IOMachPort::portForObject ( OSObject * obj, continue; if( (inst = (IOMachPort *) - dict->getObject( (const OSSymbol *) obj ))) + dict->getObject( (const OSSymbol *) obj ))) { + inst->mscount++; + inst->retain(); continue; + } inst = new IOMachPort; if( inst && !inst->init()) { @@ -149,7 +162,7 @@ IOMachPort * IOMachPort::portForObject ( OSObject * obj, if( inst->port) { // retains obj dict->setObject( (const OSSymbol *) obj, inst ); - inst->release(); // one more to free port => release obj + inst->mscount++; } else { inst->release(); @@ -163,26 +176,101 @@ IOMachPort * IOMachPort::portForObject ( OSObject * obj, return( inst ); } +bool IOMachPort::noMoreSendersForObject( OSObject * obj, + ipc_kobject_type_t type, mach_port_mscount_t * mscount ) +{ + OSDictionary * dict; + IOMachPort * machPort; + bool destroyed = true; + + IOTakeLock( gIOObjectPortLock); + + if( (dict = dictForType( type ))) { + obj->retain(); + + machPort = (IOMachPort *) dict->getObject( (const OSSymbol *) obj ); + if( machPort) { + destroyed = (machPort->mscount == *mscount); + if( destroyed) + dict->removeObject( (const OSSymbol *) obj ); + else + *mscount = machPort->mscount; + } + obj->release(); + } + + IOUnlock( gIOObjectPortLock); + + return( destroyed ); +} + void IOMachPort::releasePortForObject( OSObject * obj, ipc_kobject_type_t type ) { OSDictionary * dict; + IOMachPort * machPort; IOTakeLock( gIOObjectPortLock); if( (dict = dictForType( type ))) { obj->retain(); - dict->removeObject( (const OSSymbol *) obj ); + machPort = (IOMachPort *) dict->getObject( (const OSSymbol *) obj ); + if( machPort && !machPort->holdDestroy) + dict->removeObject( (const OSSymbol *) obj ); obj->release(); } IOUnlock( gIOObjectPortLock); } +void IOMachPort::setHoldDestroy( OSObject * obj, ipc_kobject_type_t type ) +{ + OSDictionary * dict; + IOMachPort * machPort; + + IOLockLock( gIOObjectPortLock ); + + if( (dict = dictForType( type ))) { + machPort = (IOMachPort *) dict->getObject( (const OSSymbol *) obj ); + if( machPort) + machPort->holdDestroy = true; + } + + IOLockUnlock( gIOObjectPortLock ); +} + void IOUserClient::destroyUserReferences( OSObject * obj ) { IOMachPort::releasePortForObject( obj, IKOT_IOKIT_OBJECT ); - IOMachPort::releasePortForObject( obj, IKOT_IOKIT_CONNECT ); + + // panther, 3160200 + // IOMachPort::releasePortForObject( obj, IKOT_IOKIT_CONNECT ); + + OSDictionary * dict; + + IOTakeLock( gIOObjectPortLock); + obj->retain(); + + 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->mappings) + { + dict->setObject((const OSSymbol *) uc->mappings, port); + iokit_switch_object_port(port->port, uc->mappings, IKOT_IOKIT_CONNECT); + + uc->mappings->release(); + uc->mappings = 0; + } + dict->removeObject( (const OSSymbol *) obj ); + } + } + obj->release(); + IOUnlock( gIOObjectPortLock); } mach_port_name_t IOMachPort::makeSendRightForTask( task_t task, @@ -200,6 +288,26 @@ void IOMachPort::free( void ) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +class IOUserNotification : public OSIterator +{ + OSDeclareDefaultStructors(IOUserNotification) + + IONotifier * holdNotify; + IOLock * lock; + +public: + + virtual bool init( void ); + virtual void free(); + + virtual void setNotification( IONotifier * obj ); + + virtual void reset(); + virtual bool isValid(); +}; + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + extern "C" { // functions called from osfmk/device/iokit_rpc.c @@ -222,69 +330,66 @@ ipc_port_t iokit_port_for_object( io_object_t obj, ipc_kobject_type_t type ) { IOMachPort * machPort; + ipc_port_t port; - if( (machPort = IOMachPort::portForObject( obj, type ))) - return( machPort->port ); - else - return( 0 ); + if( (machPort = IOMachPort::portForObject( obj, type ))) { + + port = machPort->port; + if( port) + iokit_retain_port( port ); + + machPort->release(); + + } else + port = NULL; + + return( port ); } kern_return_t iokit_client_died( io_object_t obj, ipc_port_t /* port */, - ipc_kobject_type_t type ) + ipc_kobject_type_t type, mach_port_mscount_t * mscount ) { IOUserClient * client; IOMemoryMap * map; + IOUserNotification * notify; - if( (IKOT_IOKIT_CONNECT == type) - && (client = OSDynamicCast( IOUserClient, obj ))) - client->clientDied(); - else if( (IKOT_IOKIT_OBJECT == type) - && (map = OSDynamicCast( IOMemoryMap, obj ))) - map->taskDied(); + if( !IOMachPort::noMoreSendersForObject( obj, type, mscount )) + return( kIOReturnNotReady ); - IOMachPort::releasePortForObject( obj, type ); + if( IKOT_IOKIT_CONNECT == type) + { + if( (client = OSDynamicCast( IOUserClient, obj ))) + client->clientDied(); + } + else if( IKOT_IOKIT_OBJECT == type) + { + if( (map = OSDynamicCast( IOMemoryMap, obj ))) + map->taskDied(); + else if( (notify = OSDynamicCast( IOUserNotification, obj ))) + notify->setNotification( 0 ); + } - return( kIOReturnSuccess); + return( kIOReturnSuccess ); } }; /* extern "C" */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -class IOUserNotification : public OSIterator +class IOServiceUserNotification : public IOUserNotification { - OSDeclareDefaultStructors(IOUserNotification) + OSDeclareDefaultStructors(IOServiceUserNotification) struct PingMsg { - mach_msg_header_t msgHdr; - OSNotificationHeader notifyHeader; + mach_msg_header_t msgHdr; + OSNotificationHeader notifyHeader; }; - PingMsg * pingMsg; - vm_size_t msgSize; - IONotifier * holdNotify; - IOLock * lock; - -public: - - virtual bool init( mach_port_t port, natural_t type, - OSAsyncReference reference, - vm_size_t messageSize ); - virtual void free(); - - virtual void setNotification( IONotifier * obj ); - - virtual void reset(); - virtual bool isValid(); -}; - -class IOServiceUserNotification : public IOUserNotification -{ - OSDeclareDefaultStructors(IOServiceUserNotification) - - enum { kMaxOutstanding = 256 }; + enum { kMaxOutstanding = 1024 }; + PingMsg * pingMsg; + vm_size_t msgSize; OSArray * newSet; OSObject * lastEntry; bool armed; @@ -306,6 +411,16 @@ class IOServiceMessageUserNotification : public IOUserNotification { OSDeclareDefaultStructors(IOServiceMessageUserNotification) + struct PingMsg { + mach_msg_header_t msgHdr; + mach_msg_body_t msgBody; + mach_msg_port_descriptor_t ports[1]; + OSNotificationHeader notifyHeader; + }; + + PingMsg * pingMsg; + vm_size_t msgSize; + public: virtual bool init( mach_port_t port, natural_t type, @@ -331,8 +446,7 @@ OSDefineAbstractStructors( IOUserNotification, OSIterator ) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -bool IOUserNotification::init( mach_port_t port, natural_t type, - OSAsyncReference reference, vm_size_t extraSize ) +bool IOUserNotification::init( void ) { if( !super::init()) return( false ); @@ -341,24 +455,6 @@ bool IOUserNotification::init( mach_port_t port, natural_t type, if( !lock) return( false ); - msgSize = sizeof( PingMsg) + extraSize; - pingMsg = (PingMsg *) IOMalloc( msgSize); - if( !pingMsg) - return( false ); - - bzero( pingMsg, msgSize); - - pingMsg->msgHdr.msgh_remote_port = port; - pingMsg->msgHdr.msgh_bits = MACH_MSGH_BITS( - MACH_MSG_TYPE_COPY_SEND, - MACH_MSG_TYPE_COPY_SEND ); - pingMsg->msgHdr.msgh_size = msgSize; - pingMsg->msgHdr.msgh_id = kOSNotificationMessageID; - - pingMsg->notifyHeader.size = extraSize; - pingMsg->notifyHeader.type = type; - bcopy( reference, pingMsg->notifyHeader.reference, sizeof(OSAsyncReference) ); - return( true ); } @@ -368,9 +464,6 @@ void IOUserNotification::free( void ) holdNotify->remove(); // can't be in handler now - if( pingMsg) - IOFree( pingMsg, msgSize); - if( lock) IOLockFree( lock ); @@ -380,10 +473,17 @@ void IOUserNotification::free( void ) void IOUserNotification::setNotification( IONotifier * notify ) { - if( holdNotify) - holdNotify->remove(); + IONotifier * previousNotify; + IOLockLock( gIOObjectPortLock); + + previousNotify = holdNotify; holdNotify = notify; + + IOLockUnlock( gIOObjectPortLock); + + if( previousNotify) + previousNotify->remove(); } void IOUserNotification::reset() @@ -411,18 +511,49 @@ bool IOServiceUserNotification::init( mach_port_t port, natural_t type, if( !newSet) return( false ); - return( super::init( port, type, reference, 0) ); + msgSize = sizeof( PingMsg) + 0; + pingMsg = (PingMsg *) IOMalloc( msgSize); + if( !pingMsg) + return( false ); + + bzero( pingMsg, msgSize); + + pingMsg->msgHdr.msgh_remote_port = port; + pingMsg->msgHdr.msgh_bits = MACH_MSGH_BITS( + MACH_MSG_TYPE_COPY_SEND /*remote*/, + MACH_MSG_TYPE_MAKE_SEND /*local*/); + pingMsg->msgHdr.msgh_size = msgSize; + pingMsg->msgHdr.msgh_id = kOSNotificationMessageID; + + pingMsg->notifyHeader.size = 0; + pingMsg->notifyHeader.type = type; + bcopy( reference, pingMsg->notifyHeader.reference, sizeof(OSAsyncReference) ); + + return( super::init() ); } void IOServiceUserNotification::free( void ) { - if( lastEntry) - lastEntry->release(); + PingMsg * _pingMsg; + vm_size_t _msgSize; + OSArray * _newSet; + OSObject * _lastEntry; - if( newSet) - newSet->release(); + _pingMsg = pingMsg; + _msgSize = msgSize; + _lastEntry = lastEntry; + _newSet = newSet; super::free(); + + if( _pingMsg && _msgSize) + IOFree( _pingMsg, _msgSize); + + if( _lastEntry) + _lastEntry->release(); + + if( _newSet) + _newSet->release(); } bool IOServiceUserNotification::_handler( void * target, @@ -431,12 +562,12 @@ bool IOServiceUserNotification::_handler( void * target, return( ((IOServiceUserNotification *) target)->handler( ref, newService )); } -bool IOServiceUserNotification::handler( void * /* ref */, +bool IOServiceUserNotification::handler( void * ref, IOService * newService ) { unsigned int count; kern_return_t kr; - IOMachPort * machPort; + ipc_port_t port = NULL; bool sendPing = false; IOTakeLock( lock ); @@ -451,13 +582,20 @@ bool IOServiceUserNotification::handler( void * /* ref */, IOUnlock( lock ); + if( kIOServiceTerminatedNotificationType == pingMsg->notifyHeader.type) + IOMachPort::setHoldDestroy( newService, IKOT_IOKIT_OBJECT ); + if( sendPing) { - if( (0 == pingMsg->msgHdr.msgh_local_port) - && (machPort = IOMachPort::portForObject( this, IKOT_IOKIT_OBJECT ) )) - pingMsg->msgHdr.msgh_local_port = machPort->port; + if( (port = iokit_port_for_object( this, IKOT_IOKIT_OBJECT ) )) + pingMsg->msgHdr.msgh_local_port = port; + else + pingMsg->msgHdr.msgh_local_port = NULL; kr = mach_msg_send_from_kernel( &pingMsg->msgHdr, pingMsg->msgHdr.msgh_size); + if( port) + iokit_release_port( port ); + if( KERN_SUCCESS != kr) IOLog("%s: mach_msg_send_from_kernel {%x}\n", __FILE__, kr ); } @@ -500,13 +638,48 @@ OSDefineMetaClassAndStructors(IOServiceMessageUserNotification, IOUserNotificati bool IOServiceMessageUserNotification::init( mach_port_t port, natural_t type, OSAsyncReference reference, vm_size_t extraSize ) { - return( super::init( port, type, reference, - sizeof(IOServiceInterestContent) + extraSize) ); + + extraSize += sizeof(IOServiceInterestContent); + msgSize = sizeof( PingMsg) + extraSize; + pingMsg = (PingMsg *) IOMalloc( msgSize); + if( !pingMsg) + return( false ); + + bzero( pingMsg, msgSize); + + pingMsg->msgHdr.msgh_remote_port = port; + pingMsg->msgHdr.msgh_bits = MACH_MSGH_BITS_COMPLEX + | MACH_MSGH_BITS( + MACH_MSG_TYPE_COPY_SEND /*remote*/, + MACH_MSG_TYPE_MAKE_SEND /*local*/); + pingMsg->msgHdr.msgh_size = msgSize; + pingMsg->msgHdr.msgh_id = kOSNotificationMessageID; + + pingMsg->msgBody.msgh_descriptor_count = 1; + + pingMsg->ports[0].name = 0; + pingMsg->ports[0].disposition = MACH_MSG_TYPE_MAKE_SEND; + pingMsg->ports[0].type = MACH_MSG_PORT_DESCRIPTOR; + + pingMsg->notifyHeader.size = extraSize; + pingMsg->notifyHeader.type = type; + bcopy( reference, pingMsg->notifyHeader.reference, sizeof(OSAsyncReference) ); + + return( super::init() ); } void IOServiceMessageUserNotification::free( void ) { + PingMsg * _pingMsg; + vm_size_t _msgSize; + + _pingMsg = pingMsg; + _msgSize = msgSize; + super::free(); + + if( _pingMsg && _msgSize) + IOFree( _pingMsg, _msgSize); } IOReturn IOServiceMessageUserNotification::_handler( void * target, void * ref, @@ -522,7 +695,7 @@ IOReturn IOServiceMessageUserNotification::handler( void * ref, void * messageArgument, vm_size_t argSize ) { kern_return_t kr; - IOMachPort * machPort; + ipc_port_t thisPort, providerPort; IOServiceInterestContent * data = (IOServiceInterestContent *) pingMsg->notifyHeader.content; @@ -540,13 +713,17 @@ IOReturn IOServiceMessageUserNotification::handler( void * ref, - sizeof( data->messageArgument) + argSize; - if( (machPort = IOMachPort::portForObject( provider, IKOT_IOKIT_OBJECT ) )) - pingMsg->msgHdr.msgh_local_port = machPort->port; - else - pingMsg->msgHdr.msgh_local_port = MACH_PORT_NULL; - + providerPort = iokit_port_for_object( provider, IKOT_IOKIT_OBJECT ); + pingMsg->ports[0].name = providerPort; + thisPort = iokit_port_for_object( this, IKOT_IOKIT_OBJECT ); + pingMsg->msgHdr.msgh_local_port = thisPort; kr = mach_msg_send_from_kernel( &pingMsg->msgHdr, - pingMsg->msgHdr.msgh_size); + pingMsg->msgHdr.msgh_size); + if( thisPort) + iokit_release_port( thisPort ); + if( providerPort) + iokit_release_port( providerPort ); + if( KERN_SUCCESS != kr) IOLog("%s: mach_msg_send_from_kernel {%x}\n", __FILE__, kr ); @@ -587,17 +764,43 @@ IOReturn IOUserClient::clientHasPrivilege( void * securityToken, security_token_t token; mach_msg_type_number_t count; - if( 0 != strcmp( privilegeName, kIOClientPrivilegeAdministrator)) - return( kIOReturnUnsupported ); - count = TASK_SECURITY_TOKEN_COUNT; kr = task_info( (task_t) securityToken, TASK_SECURITY_TOKEN, - (task_info_t) &token, &count ); - if( (kr == kIOReturnSuccess) - && (0 != token.val[0])) - kr = kIOReturnNotPrivileged; + (task_info_t) &token, &count ); + + if (KERN_SUCCESS != kr) + {} + else if (!strcmp(privilegeName, kIOClientPrivilegeAdministrator)) + { + if (0 != token.val[0]) + kr = kIOReturnNotPrivileged; + } + else if (!strcmp(privilegeName, kIOClientPrivilegeLocalUser)) + { + OSArray * array; + OSDictionary * user = 0; + + if ((array = OSDynamicCast(OSArray, + IORegistryEntry::getRegistryRoot()->copyProperty(gIOConsoleUsersKey)))) + { + for (unsigned int idx = 0; + (user = OSDynamicCast(OSDictionary, array->getObject(idx))); + idx++) + { + OSNumber * num; + if ((num = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionUIDKey))) + && (token.val[0] == num->unsigned32BitValue())) + break; + } + array->release(); + } + if (!user) + kr = kIOReturnNotPrivileged; + } + else + kr = kIOReturnUnsupported; - return( kr ); + return (kr); } bool IOUserClient::initWithTask(task_t owningTask, @@ -675,8 +878,8 @@ IOReturn IOUserClient::clientMemoryForType( UInt32 type, IOMemoryMap * IOUserClient::mapClientMemory( IOOptionBits type, task_t task, - IOOptionBits mapFlags = kIOMapAnywhere, - IOVirtualAddress atAddress = 0 ) + IOOptionBits mapFlags, + IOVirtualAddress atAddress ) { IOReturn err; IOOptionBits options = 0; @@ -778,7 +981,8 @@ IOReturn IOUserClient::sendAsyncResult(OSAsyncReference reference, if(numArgs > kMaxAsyncArgs) return kIOReturnMessageTooLarge; - replyMsg.msgHdr.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,0); + replyMsg.msgHdr.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND /*remote*/, + 0 /*local*/); replyMsg.msgHdr.msgh_size = sizeof(replyMsg) - (kMaxAsyncArgs-numArgs)*sizeof(void *); replyMsg.msgHdr.msgh_remote_port = replyPort; @@ -802,47 +1006,6 @@ IOReturn IOUserClient::sendAsyncResult(OSAsyncReference reference, /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#include - -static void makeMatchingCompatible( OSDictionary * dict ) -{ - const char * key; - const char * newKey; - OSObject * value; - OSString * str; - int i = 0; - - static const char * gratuitousNameChanges[] = { - "IOImports", kIOProviderClassKey, - "IOClass Names", kIOClassKey, - "IOProbe Score", kIOProbeScoreKey, - "IOKit Debug", kIOKitDebugKey, - "IONeededResources", kIOResourceMatchKey, - "IOName Match", kIONameMatchKey, - "IOPCI Match", kIOPCIMatchKey, - "IOPCI Primary Match", kIOPCIPrimaryMatchKey, - "IOPCI Secondary Match",kIOPCISecondaryMatchKey, - "IOPCI Class Match", kIOPCIClassMatchKey, - 0 - }; - - while( (key = gratuitousNameChanges[i++])) { - newKey = gratuitousNameChanges[i++]; - if( (value = dict->getObject( key)) - && (0 == dict->getObject( newKey))) { - - dict->setObject( newKey, value); - dict->removeObject( key); - - if( (str = OSDynamicCast(OSString, dict->getObject("CFBundleIdentifier")))) - IOLog("kext \"%s\" ", str->getCStringNoCopy()); - IOLog("must change \"%s\" to \"%s\"\n", key, newKey); - } - } -} - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - extern "C" { #define CHECK(cls,obj,out) \ @@ -855,13 +1018,100 @@ kern_return_t is_io_object_get_class( io_object_t object, io_name_t className ) { + const OSMetaClass* my_obj = NULL; + if( !object) return( kIOReturnBadArgument ); - - strcpy( className, object->getMetaClass()->getClassName()); + + my_obj = object->getMetaClass(); + if (!my_obj) { + return (kIOReturnNotFound); + } + + strcpy( className, my_obj->getClassName()); return( kIOReturnSuccess ); } +/* Routine io_object_get_superclass */ +kern_return_t is_io_object_get_superclass( + mach_port_t master_port, + io_name_t obj_name, + io_name_t class_name) +{ + const OSMetaClass* my_obj = NULL; + const OSMetaClass* superclass = NULL; + const OSSymbol *my_name = NULL; + const char *my_cstr = NULL; + + if (!obj_name || !class_name) + return (kIOReturnBadArgument); + + if( master_port != master_device_port) + return( kIOReturnNotPrivileged); + + my_name = OSSymbol::withCString(obj_name); + + if (my_name) { + my_obj = OSMetaClass::getMetaClassWithName(my_name); + my_name->release(); + } + if (my_obj) { + superclass = my_obj->getSuperClass(); + } + + if (!superclass) { + return( kIOReturnNotFound ); + } + + my_cstr = superclass->getClassName(); + + if (my_cstr) { + strncpy(class_name, my_cstr, sizeof(io_name_t)-1); + return( kIOReturnSuccess ); + } + return (kIOReturnNotFound); +} + +/* Routine io_object_get_bundle_identifier */ +kern_return_t is_io_object_get_bundle_identifier( + mach_port_t master_port, + io_name_t obj_name, + io_name_t bundle_name) +{ + const OSMetaClass* my_obj = NULL; + const OSSymbol *my_name = NULL; + const OSSymbol *identifier = NULL; + const char *my_cstr = NULL; + + if (!obj_name || !bundle_name) + return (kIOReturnBadArgument); + + if( master_port != master_device_port) + return( kIOReturnNotPrivileged); + + my_name = OSSymbol::withCString(obj_name); + + if (my_name) { + my_obj = OSMetaClass::getMetaClassWithName(my_name); + my_name->release(); + } + + if (my_obj) { + identifier = my_obj->getKmodName(); + } + if (!identifier) { + return( kIOReturnNotFound ); + } + + my_cstr = identifier->getCStringNoCopy(); + if (my_cstr) { + strncpy(bundle_name, identifier->getCStringNoCopy(), sizeof(io_name_t)-1); + return( kIOReturnSuccess ); + } + + return (kIOReturnBadArgument); +} + /* Routine io_object_conforms_to */ kern_return_t is_io_object_conforms_to( io_object_t object, @@ -954,6 +1204,31 @@ kern_return_t is_io_service_match_property_table( return( kr ); } +/* Routine io_service_match_property_table_ool */ +kern_return_t is_io_service_match_property_table_ool( + io_object_t service, + io_buf_ptr_t matching, + mach_msg_type_number_t matchingCnt, + natural_t *result, + boolean_t *matches ) +{ + kern_return_t kr; + vm_offset_t data; + vm_map_offset_t map_data; + + kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) matching ); + data = CAST_DOWN(vm_offset_t, map_data); + + if( KERN_SUCCESS == kr) { + // must return success after vm_map_copyout() succeeds + *result = is_io_service_match_property_table( service, + (char *) data, matches ); + vm_deallocate( kernel_map, data, matchingCnt ); + } + + return( kr ); +} + /* Routine io_service_get_matching_services */ kern_return_t is_io_service_get_matching_services( mach_port_t master_port, @@ -970,7 +1245,6 @@ kern_return_t is_io_service_get_matching_services( obj = OSUnserializeXML( matching ); if( (dict = OSDynamicCast( OSDictionary, obj))) { - makeMatchingCompatible( dict ); // temp for binary compatibility *existing = IOService::getMatchingServices( dict ); kr = kIOReturnSuccess; } else @@ -982,6 +1256,31 @@ kern_return_t is_io_service_get_matching_services( return( kr ); } +/* Routine io_service_get_matching_services_ool */ +kern_return_t is_io_service_get_matching_services_ool( + mach_port_t master_port, + io_buf_ptr_t matching, + mach_msg_type_number_t matchingCnt, + natural_t *result, + io_object_t *existing ) +{ + kern_return_t kr; + vm_offset_t data; + vm_map_offset_t map_data; + + kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) matching ); + data = CAST_DOWN(vm_offset_t, map_data); + + if( KERN_SUCCESS == kr) { + // must return success after vm_map_copyout() succeeds + *result = is_io_service_get_matching_services( master_port, + (char *) data, existing ); + vm_deallocate( kernel_map, data, matchingCnt ); + } + + return( kr ); +} + /* Routine io_service_add_notification */ kern_return_t is_io_service_add_notification( mach_port_t master_port, @@ -992,7 +1291,6 @@ kern_return_t is_io_service_add_notification( mach_msg_type_number_t referenceCnt, io_object_t * notification ) { - IOServiceUserNotification * userNotify = 0; IONotifier * notify = 0; const OSSymbol * sym; @@ -1015,7 +1313,6 @@ kern_return_t is_io_service_add_notification( err = kIOReturnBadArgument; continue; } - makeMatchingCompatible( dict ); // temp for binary compatibility if( (sym == gIOPublishNotification) || (sym == gIOFirstPublishNotification)) @@ -1058,6 +1355,36 @@ kern_return_t is_io_service_add_notification( return( err ); } +/* Routine io_service_add_notification_ool */ +kern_return_t is_io_service_add_notification_ool( + mach_port_t master_port, + io_name_t notification_type, + io_buf_ptr_t matching, + mach_msg_type_number_t matchingCnt, + mach_port_t wake_port, + io_async_ref_t reference, + mach_msg_type_number_t referenceCnt, + natural_t *result, + io_object_t *notification ) +{ + kern_return_t kr; + vm_offset_t data; + vm_map_offset_t map_data; + + kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) matching ); + data = CAST_DOWN(vm_offset_t, map_data); + + if( KERN_SUCCESS == kr) { + // must return success after vm_map_copyout() succeeds + *result = is_io_service_add_notification( master_port, notification_type, + (char *) data, wake_port, reference, referenceCnt, notification ); + vm_deallocate( kernel_map, data, matchingCnt ); + } + + return( kr ); +} + + /* Routine io_service_add_notification_old */ kern_return_t is_io_service_add_notification_old( mach_port_t master_port, @@ -1110,6 +1437,8 @@ kern_return_t is_io_service_add_interest_notification( } else err = kIOReturnUnsupported; + sym->release(); + } while( false ); return( err ); @@ -1277,17 +1606,45 @@ kern_return_t is_io_registry_entry_get_name( /* Routine io_registry_entry_get_name_in_plane */ kern_return_t is_io_registry_entry_get_name_in_plane( io_object_t registry_entry, - io_name_t plane, + io_name_t planeName, io_name_t name ) { + const IORegistryPlane * plane; CHECK( IORegistryEntry, registry_entry, entry ); - strncpy( name, entry->getName( IORegistryEntry::getPlane( plane )), - sizeof( io_name_t)); + if( planeName[0]) + plane = IORegistryEntry::getPlane( planeName ); + else + plane = 0; + + strncpy( name, entry->getName( plane), sizeof( io_name_t)); return( kIOReturnSuccess ); } +/* Routine io_registry_entry_get_location_in_plane */ +kern_return_t is_io_registry_entry_get_location_in_plane( + io_object_t registry_entry, + io_name_t planeName, + io_name_t location ) +{ + const IORegistryPlane * plane; + CHECK( IORegistryEntry, registry_entry, entry ); + + if( planeName[0]) + plane = IORegistryEntry::getPlane( planeName ); + else + plane = 0; + + const char * cstr = entry->getLocation( plane ); + + if( cstr) { + strncpy( location, cstr, sizeof( io_name_t)); + return( kIOReturnSuccess ); + } else + return( kIOReturnNotFound ); +} + // Create a vm_map_copy_t or kalloc'ed data for memory // to be copied out. ipc will free after the copyout. @@ -1297,15 +1654,157 @@ static kern_return_t copyoutkdata( void * data, vm_size_t len, kern_return_t err; vm_map_copy_t copy; - err = vm_map_copyin( kernel_map, (vm_offset_t) data, len, - false /* src_destroy */, ©); + err = vm_map_copyin( kernel_map, CAST_USER_ADDR_T(data), len, + false /* src_destroy */, ©); + + assert( err == KERN_SUCCESS ); + if( err == KERN_SUCCESS ) + *buf = (char *) copy; - assert( err == KERN_SUCCESS ); - if( err == KERN_SUCCESS ) - *buf = (char *) copy; return( err ); } +/* Routine io_registry_entry_get_property */ +kern_return_t is_io_registry_entry_get_property_bytes( + io_object_t registry_entry, + io_name_t property_name, + io_scalar_inband_t buf, + mach_msg_type_number_t *dataCnt ) +{ + OSObject * obj; + OSData * data; + OSString * str; + OSBoolean * boo; + OSNumber * off; + UInt64 offsetBytes; + unsigned int len = 0; + const void * bytes = 0; + IOReturn ret = kIOReturnSuccess; + + CHECK( IORegistryEntry, registry_entry, entry ); + + obj = entry->copyProperty(property_name); + if( !obj) + return( kIOReturnNoResources ); + + // One day OSData will be a common container base class + // until then... + if( (data = OSDynamicCast( OSData, obj ))) { + len = data->getLength(); + bytes = data->getBytesNoCopy(); + + } else if( (str = OSDynamicCast( OSString, obj ))) { + len = str->getLength() + 1; + bytes = str->getCStringNoCopy(); + + } else if( (boo = OSDynamicCast( OSBoolean, obj ))) { + len = boo->isTrue() ? sizeof("Yes") : sizeof("No"); + bytes = boo->isTrue() ? "Yes" : "No"; + + } else if( (off = OSDynamicCast( OSNumber, obj ))) { + offsetBytes = off->unsigned64BitValue(); + len = off->numberOfBytes(); + bytes = &offsetBytes; +#ifdef __BIG_ENDIAN__ + bytes = (const void *) + (((UInt32) bytes) + (sizeof( UInt64) - len)); +#endif + + } else + ret = kIOReturnBadArgument; + + if( bytes) { + if( *dataCnt < len) + ret = kIOReturnIPCError; + else { + *dataCnt = len; + bcopy( bytes, buf, len ); + } + } + obj->release(); + + return( ret ); +} + +/* Routine io_registry_entry_get_property */ +kern_return_t is_io_registry_entry_get_property( + io_object_t registry_entry, + io_name_t property_name, + io_buf_ptr_t *properties, + mach_msg_type_number_t *propertiesCnt ) +{ + kern_return_t err; + vm_size_t len; + OSObject * obj; + + CHECK( IORegistryEntry, registry_entry, entry ); + + obj = entry->copyProperty(property_name); + if( !obj) + return( kIOReturnNotFound ); + + OSSerialize * s = OSSerialize::withCapacity(4096); + if( !s) { + obj->release(); + return( kIOReturnNoMemory ); + } + s->clearText(); + + if( obj->serialize( s )) { + len = s->getLength(); + *propertiesCnt = len; + err = copyoutkdata( s->text(), len, properties ); + + } else + err = kIOReturnUnsupported; + + s->release(); + obj->release(); + + return( err ); +} + +/* Routine io_registry_entry_get_property_recursively */ +kern_return_t is_io_registry_entry_get_property_recursively( + io_object_t registry_entry, + io_name_t plane, + io_name_t property_name, + int options, + io_buf_ptr_t *properties, + mach_msg_type_number_t *propertiesCnt ) +{ + kern_return_t err; + vm_size_t len; + OSObject * obj; + + CHECK( IORegistryEntry, registry_entry, entry ); + + obj = entry->copyProperty( property_name, + IORegistryEntry::getPlane( plane ), options); + if( !obj) + return( kIOReturnNotFound ); + + OSSerialize * s = OSSerialize::withCapacity(4096); + if( !s) { + obj->release(); + return( kIOReturnNoMemory ); + } + + s->clearText(); + + if( obj->serialize( s )) { + len = s->getLength(); + *propertiesCnt = len; + err = copyoutkdata( s->text(), len, properties ); + + } else + err = kIOReturnUnsupported; + + s->release(); + obj->release(); + + return( err ); +} /* Routine io_registry_entry_get_properties */ kern_return_t is_io_registry_entry_get_properties( @@ -1319,7 +1818,6 @@ kern_return_t is_io_registry_entry_get_properties( CHECK( IORegistryEntry, registry_entry, entry ); OSSerialize * s = OSSerialize::withCapacity(4096); - if( !s) return( kIOReturnNoMemory ); @@ -1333,7 +1831,7 @@ kern_return_t is_io_registry_entry_get_properties( } else err = kIOReturnUnsupported; - s->release(); + s->release(); return( err ); } @@ -1350,10 +1848,12 @@ kern_return_t is_io_registry_entry_set_properties kern_return_t err; IOReturn res; vm_offset_t data; + vm_map_offset_t map_data; CHECK( IORegistryEntry, registry_entry, entry ); - err = vm_map_copyout( kernel_map, &data, (vm_map_copy_t) properties ); + err = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) properties ); + data = CAST_DOWN(vm_offset_t, map_data); if( KERN_SUCCESS == err) { @@ -1373,69 +1873,6 @@ kern_return_t is_io_registry_entry_set_properties return( err ); } - -/* Routine io_registry_entry_get_property */ -kern_return_t is_io_registry_entry_get_property( - io_object_t registry_entry, - io_name_t property_name, - io_scalar_inband_t buf, - mach_msg_type_number_t *dataCnt ) -{ - OSObject * obj; - OSData * data; - OSString * str; - OSBoolean * boo; - OSNumber * off; - UInt64 offsetBytes; - unsigned int len = 0; - const void * bytes = 0; - IOReturn ret = kIOReturnSuccess; - - CHECK( IORegistryEntry, registry_entry, entry ); - - obj = entry->getProperty( property_name ); - if( !obj) - return( kIOReturnNoResources ); - - // One day OSData will be a common container base class - // until then... - if( (data = OSDynamicCast( OSData, obj ))) { - len = data->getLength(); - bytes = data->getBytesNoCopy(); - - } else if( (str = OSDynamicCast( OSString, obj ))) { - len = str->getLength() + 1; - bytes = str->getCStringNoCopy(); - - } else if( (boo = OSDynamicCast( OSBoolean, obj ))) { - len = boo->isTrue() ? sizeof("Yes") : sizeof("No"); - bytes = boo->isTrue() ? "Yes" : "No"; - - } else if( (off = OSDynamicCast( OSNumber, obj ))) { - offsetBytes = off->unsigned64BitValue(); - len = off->numberOfBytes(); - bytes = &offsetBytes; -#if __BIG_ENDIAN__ - bytes = (const void *) - (((UInt32) bytes) + (sizeof( UInt64) - len)); -#endif - - } else - ret = kIOReturnBadArgument; - - if( bytes) { - if( *dataCnt < len) - ret = kIOReturnIPCError; - else { - *dataCnt = len; - bcopy( bytes, buf, len ); - } - } - - return( ret ); -} - - /* Routine io_registry_entry_get_child_iterator */ kern_return_t is_io_registry_entry_get_child_iterator( io_object_t registry_entry, @@ -1476,6 +1913,18 @@ kern_return_t is_io_service_get_busy_state( return( kIOReturnSuccess ); } +/* Routine io_service_get_state */ +kern_return_t is_io_service_get_state( + io_object_t _service, + uint64_t *state ) +{ + CHECK( IOService, _service, service ); + + *state = service->getState(); + + return( kIOReturnSuccess ); +} + /* Routine io_service_wait_quiet */ kern_return_t is_io_service_wait_quiet( io_object_t _service, @@ -1524,6 +1973,10 @@ kern_return_t is_io_service_open( kern_return_t is_io_service_close( io_object_t connection ) { + OSSet * mappings; + if ((mappings = OSDynamicCast(OSSet, connection))) + return( kIOReturnSuccess ); + CHECK( IOUserClient, connection, client ); client->clientClose(); @@ -1585,7 +2038,10 @@ kern_return_t is_io_connect_map_memory( if( task != current_task()) { // push a name out to the task owning the map, // so we can clean up maps - mach_port_name_t name = IOMachPort::makeSendRightForTask( +#if IOASSERT + mach_port_name_t name = +#endif + IOMachPort::makeSendRightForTask( task, map, IKOT_IOKIT_OBJECT ); assert( name ); @@ -1607,6 +2063,33 @@ kern_return_t is_io_connect_map_memory( return( err ); } +IOMemoryMap * IOUserClient::removeMappingForDescriptor(IOMemoryDescriptor * mem) +{ + OSIterator * iter; + IOMemoryMap * map = 0; + + IOLockLock(gIOObjectPortLock); + + iter = OSCollectionIterator::withCollection(mappings); + if(iter) + { + while ((map = OSDynamicCast(IOMemoryMap, iter->getNextObject()))) + { + if(mem == map->getMemoryDescriptor()) + { + map->retain(); + mappings->removeObject(map); + break; + } + } + iter->release(); + } + + IOLockUnlock(gIOObjectPortLock); + + return (map); +} + kern_return_t is_io_connect_unmap_memory( io_object_t connect, int type, @@ -1629,14 +2112,28 @@ kern_return_t is_io_connect_unmap_memory( map = memory->map( task, mapAddr, options ); memory->release(); - if( map) { + if( map) + { IOLockLock( gIOObjectPortLock); if( client->mappings) client->mappings->removeObject( map); - IOMachPort::releasePortForObject( map, IKOT_IOKIT_OBJECT ); IOLockUnlock( gIOObjectPortLock); - map->release(); - } else + + mach_port_name_t name = 0; + if (task != current_task()) + name = IOMachPort::makeSendRightForTask( task, map, IKOT_IOKIT_OBJECT ); + if (name) + { + map->unmap(); + err = iokit_mod_send_right( task, name, -2 ); + err = kIOReturnSuccess; + } + else + IOMachPort::releasePortForObject( map, IKOT_IOKIT_OBJECT ); + if (task == current_task()) + map->release(); + } + else err = kIOReturnBadArgument; } @@ -2313,8 +2810,12 @@ kern_return_t is_io_catalog_send_data( if(flag != kIOCatalogRemoveKernelLinker && ( !inData || !inDataCount) ) return kIOReturnBadArgument; - if (data) { - kr = vm_map_copyout( kernel_map, &data, (vm_map_copy_t)inData); + if (inData) { + vm_map_offset_t map_data; + + kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t)inData); + data = CAST_DOWN(vm_offset_t, map_data); + if( kr != KERN_SUCCESS) return kr; @@ -2337,12 +2838,6 @@ kern_return_t is_io_catalog_send_data( array = OSDynamicCast(OSArray, obj); if ( array ) { -//-- - OSDictionary * dict; - int i = 0; - while( (dict = OSDynamicCast(OSDictionary, array->getObject(i++)))) - makeMatchingCompatible( dict ); -//-- if ( !gIOCatalogue->addDrivers( array , flag == kIOCatalogAddDrivers) ) { kr = kIOReturnError; @@ -2360,7 +2855,6 @@ kern_return_t is_io_catalog_send_data( dict = OSDynamicCast(OSDictionary, obj); if ( dict ) { - makeMatchingCompatible( dict ); if ( !gIOCatalogue->removeDrivers( dict, flag == kIOCatalogRemoveDrivers ) ) { kr = kIOReturnError; @@ -2377,7 +2871,6 @@ kern_return_t is_io_catalog_send_data( dict = OSDynamicCast(OSDictionary, obj); if ( dict ) { - makeMatchingCompatible( dict ); if ( !gIOCatalogue->startMatching( dict ) ) { kr = kIOReturnError; } @@ -2391,6 +2884,8 @@ kern_return_t is_io_catalog_send_data( case kIOCatalogRemoveKernelLinker: { if (gIOCatalogue->removeKernelLinker() != KERN_SUCCESS) { kr = kIOReturnError; + } else { + kr = kIOReturnSuccess; } } break; @@ -2481,17 +2976,8 @@ kern_return_t is_io_catalog_get_data( return kIOReturnNoMemory; s->clearText(); - switch ( flag ) { - case kIOCatalogGetContents: - if ( !gIOCatalogue->serialize(s) ) { - kr = kIOReturnNoMemory; - } - break; - default: - kr = kIOReturnBadArgument; - break; - } + kr = gIOCatalogue->serializeData(flag, s); if ( kr == kIOReturnSuccess ) { vm_offset_t data; @@ -2499,10 +2985,11 @@ kern_return_t is_io_catalog_get_data( vm_size_t size; size = s->getLength(); - kr = vm_allocate(kernel_map, &data, size, true); + kr = vm_allocate(kernel_map, &data, size, VM_FLAGS_ANYWHERE); if ( kr == kIOReturnSuccess ) { bcopy(s->text(), (void *)data, size); - kr = vm_map_copyin(kernel_map, data, size, true, ©); + kr = vm_map_copyin(kernel_map, (vm_map_address_t)data, + (vm_map_size_t)size, true, ©); *outData = (char *)copy; *outDataCount = size; } @@ -2568,31 +3055,32 @@ kern_return_t is_io_catalog_reset( return kIOReturnSuccess; } -kern_return_t iokit_user_client_trap(io_object_t userClientRef, UInt32 index, void *p1, void *p2, void *p3, void *p4, void *p5, void *p6) +kern_return_t iokit_user_client_trap(struct iokit_user_client_trap_args *args) { - kern_return_t result = kIOReturnBadArgument; - IOUserClient *userClient; + kern_return_t result = kIOReturnBadArgument; + IOUserClient *userClient; - if ((userClient = OSDynamicCast(IOUserClient, iokit_lookup_connect_ref_current_task(userClientRef)))) { - IOExternalTrap *trap; - IOService *target = NULL; + if ((userClient = OSDynamicCast(IOUserClient, + iokit_lookup_connect_ref_current_task((OSObject *)(args->userClientRef))))) { + IOExternalTrap *trap; + IOService *target = NULL; - trap = userClient->getTargetAndTrapForIndex(&target, index); + trap = userClient->getTargetAndTrapForIndex(&target, args->index); - if (trap && target) { - IOTrap func; + if (trap && target) { + IOTrap func; - func = trap->func; + func = trap->func; - if (func) { - result = (target->*func)(p1, p2, p3, p4, p5, p6); - } - } + if (func) { + result = (target->*func)(args->p1, args->p2, args->p3, args->p4, args->p5, args->p6); + } + } - userClient->release(); - } + userClient->release(); + } - return result; + return result; } }; /* extern "C" */