Question

In my kext's stop() function, I call iflt_detach() to detach a registered iff filter. However, it appears that (for whatever reasons), the filter's detach() function may be called outside of the stop() function. In that case, what should I do in the stop function? I can't return KERN_SUCCESS since that would cause the KEXT to get unloaded with obvious side-effects for the delayed call to the detach() function.

The following snippet is from enetlognke.c and shows the stop() function:

kern_return_t com_dts_apple_kext_enetlognke_stop (kmod_info_t * ki, void * d)
{ kern_return_t retval = KERN_FAILURE; // default result, unless we know that we are
// detached from the interface.

if (gFilterRegistered == FALSE) 
    return KERN_SUCCESS; 

if (gUnregisterProc_started == FALSE) 
{ 
    // only want to start the detach process once. 
    iflt_detach(gEnetFilter); 
    gUnregisterProc_started = TRUE; 
} 

if (gUnregisterProc_complete) 
{ 
    retval = KERN_SUCCESS; 
} 
else 
{ 
    el_printf("enetlognke_stop: incomplete\n"); 
} 

if (retval == KERN_SUCCESS) 
{ 
// Free KEXT resources
} 
return retval; 

}

gUnregisterProc_complete is set to TRUE from within this module's dispatch() function. So, if that function call is delayed (and gUnregisterProc_complete is FALSE), the stop function would veto the unload by returning KERN_FAILURE.

So, my questions are:

  1. If KERN_FAILURE is returned, will the kernel call the KEXT's stop() function again? If not, what triggers a retry of the KEXT unload and the call to the stop() function?

  2. Is KERN_FAILURE the correct code to return is the filter has not been detached?

No correct solution

OTHER TIPS

Presumably, the detach function will in this case be called on another thread, once there are no threads remaining running your callbacks?

If so, this becomes a fairly straightforward thread synchronisation problem. Set up a flag variable, e.g. has_detached and protect it by a recursive mutex.

In the stop function: Lock the mutex before calling iflt_detach(). If on return, the flag hasn't been set, sleep on the flag's address while suspending the mutex, until the flag is set. Finally, unlock, and return from the stop function.

At the very end of your detach function: lock the mutex, set the flag, send a wakeup to the potentially sleeping thread and unlock. If the unlock call is in the tail position, there is no race condition between executing your detach function's code and unloading said code.

Effectively, this will block the unloading of the kext until your filter has fully detached.

Note: I haven't tried this in this particular case of network filters (I have yet to write a filter kext), but it's generally a pattern I've used a lot in other kexts.

Note 2: I say use a recursive lock to guard against deadlock in case your detach function does get called on the same thread while inside iflt_detach().

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top