Can't Unload Kernel Extension; Classes Have Instances - macos

I'm writing an OSX kernel extension for an audio device driver (it's software, but emulates a hardware device).
During development, it'd be convenient to completely uninstall existing old versions and then build and install the new version from scratch. However, this occasionally seems to not be possible without a system restart.
The program itself is not running and the source files have been deleted from the /System/Library/Extensions/ dir.
But kextstat reveals a single instance:
$ kextstat | grep 'com.foo.driver.bar'
219 0 0xfff123 0x5000 0x5000 com.foo.driver.bar (0.0.1) <102 5 4 3>
(...meaning:)
Index Refs Address Size Wired Name (Version) <Linked Against>
So there are 0 Refs to my driver instance, but kextunload will sometimes fail, complaining of existing instances:
$ sudo kextunload -b com.foo.driver.bar
(kernel) Can't unload kext com.foo.driver.bar; classes have instances:
(kernel) Kext com.foo.driver.bar class FooBarDriver has 1 instance.
(kernel) Kext com.foo.driver.bar class com_foo_driver_bar has 1 instance.
Failed to unload com.foo.driver.bar - (libkern/kext) kext is in use or retained (cannot unload).
When this happens, there's no way to "force" unload the kext (that I know of).
Am I right in guessing that this single instance still exists because of a reference held in memory by the running OS kernel? That doesn't seem right, because then kextunload would always fail. So why does kextunload only sometimes require a system restart to "fully" unload all driver instances?

Running kextunload for an IOKit kext will (if no other kexts depend on it) cause the kernel to attempt to terminate() any instances of classes in that kext which are in the I/O Kit registry. It will then wait a bit and check if any of that kext's classes still have instances. If not, it will unload the kext. If instances remain, kextunload fails (the terminated instances stay terminated, though; by this I mean that I/O kit matching is not re-run on their providers).
So somehow, you're still ending up with live instances.
One possibility is that your objects are refusing to terminate(). This can happen if they have clients that won't give up control, e.g. you can't unload the driver for a disk with a mounted file system on top. Userspace clients that don't respond to termination messages are another example.
Otherwise, the instances terminate, but are not freed. Since they seem to be of two of your main driver classes, if you don't have any user clients that won't give up their claim, I'm going to go out on a limb and suggest that you might have a circular reference. If that's not it, you'll just have to hunt for retain()s which are not matched by a release(). I give some tips on how to track these down in this answer.
If the instances terminate and are deregistered, they will no longer appear in the output of the ioreg commandline tool, so that's an easy way of checking which of the two cases applies here.

Related

How to use atos to properly symbolicate addresses from OSReportWithBacktrace?

I am trying to hunt down retain leaks in an open-source project to support I2C based trackpads (https://github.com/kprinssu/VoodooI2CHID).
The reason why I believe that there are retain leaks is because when I attempt to unload the kernel extension via the following commands:
sudo kextunload -verbose 6 VoodooI2CHID.kext
I get the following output:
Kext user-space log filter changed from 0xff2 to 0xfff.
Kext kernel-space log filter changed from 0xff2 to 0xfff.
Kext library architecture set to x86_64.
Requesting unload of com.alexandred.VoodooI2CHID (with termnation of IOServices).
(kernel) User-space log flags changed from 0x0 to 0xfff.
(kernel) Received 'Unload' request from user space.
(kernel) Rescheduling scan for unused kexts in 60 seconds.
(kernel) Can't unload kext com.alexandred.VoodooI2CHID; classes have instances:
(kernel) Kext com.alexandred.VoodooI2CHID class VoodooI2CPrecisionTouchpadHIDEventDriver has 1 instance.
(kernel) Kext com.alexandred.VoodooI2CHID class VoodooI2CMultitouchHIDEventDriver has 1 instance.
Kernel error handling kext request - (libkern/kext) kext is in use or retained (cannot unload).
Failed to unload com.alexandred.VoodooI2CHID - (libkern/kext) kext is in use or retained (cannot unload).
I came across pmdj's excellent answer on tracking down retain leaks (Can't Unload Kernel Extension; Classes Have Instances). I verfied that my situation is the second case via ioreg (classes are being terminated but are not properly freed). Additionally, I used pmdj's hint by overiding taggedRelease and taggedRetain (https://stackoverflow.com/a/13471512/48660) to print the stack trace of the function calls.
Here's where I run into problems, I cannot use atos to convert the hex addresses back into human readable symbols. I use the follow command to generate the symbols:
atos -arch x86_x64 -o VoodooI2C.kext/Contents/MacOS/VoodooI2C -l 0xffffff7f8432b000 0xffffff804588dfa0
The load address parameter is retrieved from kextstat and I expect the -l argument should handle the slide arithmetic.
atos should return a valid symbol but all I get is the hex address back. In the above example, I get 0xffffff804588dfa0 as the output. Can anybody point out what I exactly I am missing?
Both kextstat and OSReportWithBacktrace report unslid addresses, so KASLR is not your problem.
Notice that your kext is apparently loaded at 0xffffff7f8432b000, whereas your backtrace frame address is 0xffffff804588dfa0. This is quite far apart, and indeed kexts are always loaded in the 0xffffff7f8??????? (unslid) range, so 0xffffff804588dfa0 can't be anywhere near kext code. (the offset is about 3GB) It's almost certainly a function in the kernel proper. If you use atos with the appropriate running kernel's binary, it should be able to locate which one. For example:
atos -o /Library/Developer/KDKs/KDK_10.14.5_18F132.kdk/System/Library/Kernels/kernel 0xffffff804588dfa0
(I don't know what kernel version you are using, and this address doesn't seem to be meaningful in the 18F132 kernel, but you get the idea.)

Load OS X kext in the early boot process

I have a working OSX kernel extension which I would like to be automatically loaded at boot time as early as possible. The kext is using KAUTH for monitoring access on a specific path so it seems to me there won't be anything that will request it to be loaded into the kernel. In this case, copying it in /Library/Extensions (at least since Yosemite this is the recommended path for third-party extensions) won't solve my problem.
Is there a possibility to achieve this, whether or not by modifying the code or through some auxiliary configuration?
I already read about using a launchd daemon to use kextload in order to load the extension, as specified in this question, but in my case, I want it to be loaded as early as possible.
Update:
I am using a "generic" kernel extension (linked against BSD library) and not an I/O Kit based one.
I want my extension to be loaded before launchd is started.
You don't explicitly state it in the question, but I infer from the context that you're using a "generic" kernel extension (in contrast to an I/O kit based one)? These are only loaded either because another kext depends on them, or because they are explicitly loaded via kextutil/kextload or the KextManager API.
Contrast this to I/O Kit kexts, which are loaded on-demand when one of their personality dictionaries matches a registered service in the IO registry. This is usually for driving specific devices, but various non-hardware-dependent system services use the mechanism to match the 'IOResources' nub (documentation) which turns up during early boot so any kexts listing it as a provider for a personality also get loaded on boot.
So the solution would be to modify your kext to provide an IOService which matches the IOResources nub. The service itself doesn't really need to do anything if your userspace component already uses another interface to communicate with the kext.
If you don't want to change the kext's code itself, you could possibly create a dummy kext which does this, but declares your main kext as a dependency. This latter method isn't particularly elegant, but should work if for some reason modifying the existing kext is not possible. (Although you'll likely need to modify the info.plist)
If the kext is derived from IOKit and resides in /Library/Extensions clear the cache and it will be automatically loaded at boot. You clear the cache by calling
kextcache -f -update-volume /

Detect if OS X kernel extension is loadable

I'm attempting to write an application that talks to a custom USB device. We have written a driver (kext) that is automatically loaded when the USB device is attached to the computer. It is installed into the appropriate location (/System/Library/Extensions & /Library/Extensions) during the installation process.
In my application (.app), I need to be able to confirm that this kext is installed and is loadable on the user's computer.
My initial thought was to use the "System" command and get the result of "kextstat | grep mykext". However, kextstat only shows the kernel extensions that are loaded. (It's possible the application can be launched before the user has attached the USB device).
The only other thing that I can think of is to use "kextfind | grep mykext" to determine if the kext exists, however, I don't know if it is loadable or not. (ie. it could exist, but someone messed with the plist file, and now the signature fails, so it won't ever be loaded)
I know that it's possible, because Apple's System Profiler is able to list all of the extensions, if they are loaded, and if they are loadable.
From the kextutil man page:
kextutil prints diagnostic information about kexts by default, but some options cause certain tests to be skipped. To ensure that all tests are performed, use the -print-diagnostics (-t) option. The -print-diagnostics option is typically used with -no-load (-n) after a load failure to pinpoint a problem. It can be used with any other set of options, however.
Note: when the -no-load (-n) option is used then sudo (root user) isn't required.

Read plist from kext

I'd like save a kext setting between OS restarts. As I need the settings after kext been loaded immediately, I can not wait for managing daemon start up. Is it a way for reading/writing kext plist file from kext or some other ways to do that?
Basically, no - you're supposed to store settings in userspace and use a launchd service to set them in the kext. Until your kext receives the settings, it should just use some sane defaults.
One way to truly include settings on kext startup is to add custom attributes to the IOKitPersonality in your kext's info.plist. Obviously, this means that changing settings requires changing the kext itself, but I have heard reports of people actually doing this on Apple's public darwin mailing lists (although Apple employees pitched in to criticise it). Note that the kext cache will not like this: If your userspace program changes settings in the info.plist, it will probably need to increase the bundle version number in order for the kext cache to pick up the change, otherwise the cached/prelinked kext won't see the change. You need to do this within the constraints of the rules for kext bundle versions or it won't be detected as a version increase, or worse, the kext cache will reject the kext outright. Also, don't forget to touch /System/Library/Extensions/ after updating kexts.
Update: modifying a kext's info.plist will no longer work in 10.9 and 10.10 due to the kext signing requirement.
In the specific case where your kext is a storage filter scheme, you can store your settings in a special "super block" of the provider partition. AppleRAID (which is open source) does this, for example. This isn't practical for any other kind of kext, though.

Mac: load Mass Storage Driver Kext for testing

I am writing a customised mass storage kernel extension for Mac, subclassed from the IOSCSIPeripheralDeviceType05 logical unit driver. I have got as far as compiling a .kext file, which passes kextutil -n -t ..., but I cannot load it for testing.
I have a non-zero IOKitDebug field in the .plist, and the GetDeviceConfiguration looks like this:
IOReturn
com_MyCompany_driver_MyDriver::GetDeviceConfiguration( void )
{
IOLog( "MyDriver overriding GetConfiguration\n" );
return super::GetDeviceConfiguration();
}
However when I copy it into /System/Library/Extensions/ and execute it with kextutil /System/Library/Extension/MyDriver.kext, nothing happens, and nothing appears in /var/log/system.log.
How do I load this .kext to be able to debug it?
First, don't put extensions in /SLE while developing them. That's asking for trouble, as it can cause the extension to be loaded automatically. This could cause the system to become unbootable. Just copy to, e.g. /tmp/ and use kextutil to load it from there.
Second, put some debug output in com_MyCompany_driver_MyDriver::init() as that's the first thing that'll get called.
Third, your problem is likely the device matching. If the device is already matched by an existing driver at the time of loading your kext, yours won't be considered. If you can't hot-plug the device and you can't unload the existing driver before loading yours, you may need to install the kext in SLE to be loaded on boot after all. If you're still having matching trouble, post some details of the device you're trying to match (ioreg/IORegistryExplorer output) and the matching dictionary from your info.plist.

Resources