IOService leaking for NO reason

送分小仙女□ 提交于 2019-12-24 07:38:10

问题


Okay, I am completely stumped and frustrated. I was working on an I/O Kit RAM Disk implementation and discovered that it wasn't unloading when my friend loaded it with kextload and then tried to unload it with kextunload. The reason for this was that none of the OSObjects which the kext allocated were being freed. However, on both my computer (running Mac OS 10.8.5) and a VM (running Mac OS 10.7) everything worked as expected.

Eventually, I narrowed the problem down so much that I created a new Xcode project with a blank I/O Kit driver and tested it on my friend's machine. Lo and behold, I was unable to unload the module with kextunload because it was claiming that my IOService subclass was leaking. I would like to test another driver on my friend's machine where I don't override any IOService methods (in the version I tested, I override a few to do IOLogs before passing the call to super). I will update this with any extra information I collect about his machine's configuration.

Here is my header (BrokenDriver.h):

#include <IOKit/IOService.h>
#include <IOKit/IOLib.h>

class BrokenDriver : IOService {
    OSDeclareDefaultStructors(BrokenDriver)
public:
    virtual bool init(OSDictionary * dictionary = NULL);
    virtual void free();

    virtual bool start(IOService * provider);
    virtual void stop(IOService * provider);
};

And here is my implementation (BrokenDriver.cpp):

#define super IOService
OSDefineMetaClassAndStructors(BrokenDriver, IOService);

bool BrokenDriver::start(IOService * provider) {
    bool success;
    IOLog("%s[%p]::%s(%p)\n", getName(), this, __FUNCTION__, provider);
    success = super::start(provider);
    if (success) {
        // Don't worry, the problem persists even if I don't call registerService()
        registerService();
    }
    return success;
}

void BrokenDriver::stop(IOService * provider) {
    IOLog("%s[%p]::%s(%p)\n", getName(), this, __FUNCTION__, provider);    
    super::stop(provider);
}

bool BrokenDriver::init(OSDictionary * dictionary) {
    if (!super::init(dictionary)) {
        return false;
    }    
    IOLog("%s[%p]::%s(%p)\n", getName(), this, __FUNCTION__, dictionary);
    return true;
}

void BrokenDriver::free(void) {
    IOLog("%s[%p]::%s()\n", getName(), this, __FUNCTION__);
    super::free();
}

Additionally, since I know this could be the source of problems, here is the XML of my BrokenDriver-Info.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleDevelopmentRegion</key>
    <string>English</string>
    <key>CFBundleExecutable</key>
    <string>${EXECUTABLE_NAME}</string>
    <key>CFBundleIconFile</key>
    <string></string>
    <key>CFBundleIdentifier</key>
    <string>com.aqnichol.${PRODUCT_NAME:rfc1034identifier}</string>
    <key>CFBundleInfoDictionaryVersion</key>
    <string>6.0</string>
    <key>CFBundleName</key>
    <string>${PRODUCT_NAME}</string>
    <key>CFBundlePackageType</key>
    <string>KEXT</string>
    <key>CFBundleShortVersionString</key>
    <string>1.0</string>
    <key>CFBundleSignature</key>
    <string>????</string>
    <key>CFBundleVersion</key>
    <string>1</string>
    <key>NSHumanReadableCopyright</key>
    <string>Copyright © 2013 Alex Nichol. All rights reserved.</string>
    <key>IOKitPersonalities</key>
    <dict>
        <key>BrokenDriver</key>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>com.aqnichol.BrokenDriver</string>
            <key>IOClass</key>
            <string>BrokenDriver</string>
            <key>IOKitDebug</key>
            <integer>65535</integer>
            <key>IOMatchCategory</key>
            <string>BrokenDriver</string>
            <key>IOProbeScore</key>
            <integer>1000</integer>
            <key>IOProviderClass</key>
            <string>IOResources</string>
            <key>IOResourceMatch</key>
            <string>IOKit</string>
        </dict>
    </dict>
    <key>OSBundleLibraries</key>
    <dict>
        <key>com.apple.kpi.iokit</key>
        <string>9.0.0</string>
        <key>com.apple.kpi.libkern</key>
        <string>9.0.0</string>
        <key>com.apple.kpi.mach</key>
        <string>9.0.0</string>
    </dict>
</dict>
</plist>

So, what's the verdict? Is my friend's kernel fried, or is it my brain? Is it even remotely possible that some other driver on his machine is attempting to persist my kext?

UPDATE: I tried again with an EMPTY implementation. That's right, I overrode exactly 0 methods of my own. The problem persists. Here is the message from kextunload:

(kernel) Can't unload kext com.aqnichol.BrokenDriver; classes have instances:
(kernel) Kext com.aqnichol.BrokenDriver class BrokenDriver has 1 instance.
Failed to unload com.aqnichol.BrokenDriver - (libkern/kext) kext is in use or retained (cannot unload).

回答1:


I have no idea if this is the problem, but I notice that IOService is a private base of your class. I could imagine that this might trigger some subtle issues in Apple's runtime type info macros?

Try:

class BrokenDriver : public IOService


来源:https://stackoverflow.com/questions/19353162/ioservice-leaking-for-no-reason

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!