【问题标题】:Driver causing sleep wake failure驱动程序导致睡眠唤醒失败
【发布时间】:2015-04-13 16:54:03
【问题描述】:

作为一项安全研究,我正在编写一个自定义 IOKit 驱动程序。驱动程序通过电源层将自身注册到它所依赖的驱动程序。 (USB 服务)。正在调用setPowerState 函数并且驱动程序正确地自行关闭。

问题是,它会随机导致睡眠唤醒失败问题,并且机器会自行重启。实际上重置发生在机器进入睡眠后唤醒期间(显然试图休眠)

问题是,我该如何调试或解决它?我正在使用火线内核调试来查看发生了什么,但是调试器和断点导致睡眠计时机制出现延迟,一切都一团糟。

互联网上的数据在这个问题上相当薄弱,但充满了关于 OSX 机器在干净的机器中导致睡眠唤醒失败的抱怨。

我正在各种机器和内核版本上对其进行测试,并且它是持久的。

任何线索都会有所帮助。

编辑:附加代码

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;
}

【问题讨论】:

  • 你确定机器没有内核恐慌吗?也可能 SMC 的编程方式是,在唤醒过程中的长时间延迟使其认为机器已冻结(并且可能由于您的驱动程序中的无限循环或其他原因而被冻结)。
  • 你能把问题减少到一个超级最小的 kext 吗?这似乎不是我们可以在没有任何代码的情况下帮助您调试的事情。

标签: macos debugging kernel iokit xnu


【解决方案1】:

IOService 的未释放引用导致睡眠序列中出现死锁。

我们使用以下代码获取IOService指针。

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

IOService::serviceMatchingIOService::waitForService 都会增加引用计数器。

改为如下示例代码:

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

if (dict == NULL)
    return NULL;

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

dict->release();

return service;

IOService::waitForMatchingService 增加引用计数器,我们释放OSDictionary 指针。

【讨论】:

    猜你喜欢
    • 2014-07-29
    • 1970-01-01
    • 2012-10-08
    • 2018-12-04
    • 1970-01-01
    • 1970-01-01
    • 2011-07-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多