4

As a security research I am writing a custom IOKit driver. The driver registers itself through the power plane to drivers it depends on. (USB services). The setPowerState function is being called and the driver shutdown itself correctly.

Problem is, randomly it causes sleep wake failures issues and the machine restarts itself. Actually the reset occurs during a wakeup of the machine after it entered sleep (trying to hibernate apparently)

Question is, how can I debug or solve it? I am using a firewire kernel debugging to view what is going on, but the debugger and the breakpoints are causing delays in the sleep timing mechanism and everything is a mess.

Data in the internet is pretty weak regarding this issue but full of complains about OSX machines causing sleep wake failures in a clean machines.

I am testing it on various machines and kernel versions and it is persistent.

Any clue will help.

EDIT: Additional code

enum
{
    kOffPowerState, kStandbyPowerState, kIdlePowertState, kOnPowerState, kNumPowerStates
};

static IOPMPowerState gPowerStates[kNumPowerStates]   =
{
    //kOffPowerState
    {kIOPMPowerStateVersion1, 0,0,0,0,0,0,0,0,0,0,0},

    //kStandbyPowerState
    {kIOPMPowerStateVersion1, kIOPMPowerOn, kIOPMPowerOn, kIOPMPowerOn, 0,0,0,0,0,0,0,0},

    //kIdlePowerState
    {kIOPMPowerStateVersion1, kIOPMPowerOn, kIOPMPowerOn, kIOPMPowerOn, 0,0,0,0,0,0,0,0},

    //kOnPowerState
    {kIOPMPowerStateVersion1, kIOPMPowerOn | kIOPMDeviceUsable, kIOPMPowerOn, kIOPMPowerOn, 0,0,0,0,0,0,0,0}
};

bool driver::start(IOService* provider)
{
    IOLog("driver::start\n");

    if (IOService::start(provider) == false)
        return false; 

   PMinit();

   provider->joinPMtree(this);    
   makeUsable();
   changePowerStateTo(0);
   registerPowerDriver(this, gPowerStates, kNumPowerStates);
   registerService();
   return true;
}

IOReturn driver::setPowerState (unsigned long whichState, IOService * whatDevice)
{
    IOLog("driver::setPowerState (%lu)\n", whichState);

    if (whichState == 0)
        IOLog("driver: shutdown (%lu)\n", whichState);

    return kIOPMAckImplied;
}
jww
  • 97,681
  • 90
  • 411
  • 885
mrdvlpr
  • 526
  • 4
  • 20
  • 1
    are you sure that the machine isnt kernel panicking? also maybe the SMC is programmed in such a way that a long delay in the wake makes it think the machine is frozen (and maybe it is frozen due to an infinite loop in your driver or something). – Brad Allred Feb 12 '15 at 21:46
  • Can you reduce the problem to a super minimal kext? This doesn't seem like the kind of thing we can help you debug without any code. – pmdj Feb 13 '15 at 13:20

1 Answers1

1

An unreleased reference to IOService caused a dead lock in the sleep sequence.

We used the following code to obtain IOService pointers.

mach_timespec time;
time.tv_sec = 0;
time.tv_nsec = 1000;
IOService* service = IOService::waitForService(IOService::serviceMatching(class_name, NULL), &time);
return service; 

both IOService::serviceMatching and IOService::waitForService increase reference counters.

Changed to the following example code:

OSDictionary *dict = IOService::serviceMatching(class_name, NULL);

if (dict == NULL)
    return NULL;

IOService* service = IOService::waitForMatchingService(dict, 1000);

dict->release();

return service;

IOService::waitForMatchingService does not increase a reference counter and we release the OSDictionary pointer.

mrdvlpr
  • 526
  • 4
  • 20
  • I understand it's a quite old post, but I encountered exactly the same problem. I am learning and unfortunately do not understand your answer. Could you please explain, do you mean that I should not use IOService* provider in the IOService::start, but your (or similar) code instead? Do I need to use it somewhere else? Thank you! – BUKTOP Mar 25 '23 at 13:19