4

it's my first question here :)

I'm currently writing a generic kext which provides a character device and targets OSX 10.7+. It's pure C, with zero IOKit/C++. (In case this matters, I'm testing the driver on 10.11.)

I want the driver to be unloaded once all file descriptors that refer to the character device are closed, but this doesn't seem to work.

According to Apple's documentation for OSKextRetainKextWithLoadTag:

When autounload is enabled, then shortly after the kext's last reference is dropped, it will be unloaded if there are no outstanding references to it and there are no instances of its Libkern C++ subclasses (if any).

...

Kexts that define subclasses of IOService have autounload enabled automatically. Other kexts can use the reference count to manage automatic unload without having to define and create Libkern C++ objects.

As mentioned above, my kext doesn't have any IOService subclasses (or any classes, for that matter), so I should be able to use OSKextRetainKextWithLoadTag.

However, the kext remains loaded forever, after all file descriptors are closed:

static int cdev_open(dev_t dev, int flags, int devtype, struct proc *p)
{
    /* ... */

    return OSKextRetainKextWithLoadTag(OSKextGetCurrentLoadTag()) == kOSReturnSuccess) ? 0 : kOSReturnError
}

static int cdev_close(dev_t dev, int flags, int devtype, struct proc *p)
{
    /* ... */

   OSKextReleaseKextWithLoadTag(OSKextGetCurrentLoadTag());
   return 0;
}

In addition, I wrote "hybrid" version of my kext, where I wrapped the start and stop routines with a thin C++ wrapper that provides a IOService subclass (with IOResources as the provider), in case unloading is no longer supported with generic kexts. Same result.

(I've found several examples of generic kexts that use OSKextRetainKextWithLoadTag and OSKextReleaseKextWithLoadTag , but they're extremely old and don't know if they work against recent versions of OS X.)

Any idea what I'm doing wrong?

Thank you.

dimkr
  • 41
  • 3
  • 1
    Does the kext unload cleanly when unloaded manually with `kextunload`? This is a prerequisite we need to get out of the way before we can look any deeper. – pmdj Sep 19 '16 at 11:05
  • Yep, no issues with that. Also, it cannot be unloaded while there is an open file descriptor (due to the `OSKextRetainKextWithLoadTag` call; retaining is confirmed to work). – dimkr Sep 19 '16 at 19:33

1 Answers1

1

Consider the following generic kext:

kern_return_t xxxKext_start(kmod_info_t * ki, void *d)
{
    // this should set auto unload enabled 
    // and retain a refcount on the kext
    OSKextRetainKextWithLoadTag(OSKextGetCurrentLoadTag());

    // this should call OSKext::considerUnloads()
    // and remove the search retain and the previous call retain
    OSKextReleaseKextWithLoadTag(OSKextGetCurrentLoadTag());

    // somewhere here or even before - kext suppose to be unloaded automatically (according to Apple docs)
    return KERN_SUCCESS;
}

kern_return_t xxxKext_stop(kmod_info_t *ki, void *d)
{
   return KERN_SUCCESS;
}

This kext should automatically disappear after a short time regardless of calling kextunload or something similar.

in 10.12.1 it works perfectly. After a while (not that short delay they describe in their docs), it will disappear from the kextstat command.

In 10.11.6 though it will remain loaded for some reason.

So you are not doing anything wrong, it is just broken in some releases.

mrdvlpr
  • 526
  • 4
  • 20