某些需要root权限的IOServiceOpen()调用的解决方法

时间:2019-01-14 01:02:31

标签: macos power-management iokit

背景

可以通过创建DisableInflow电源管理声明来对Mac笔记本电脑的电源适配器执行软件控制的断开连接。

来自this answer to an SO question

代码可用于创建所述断言。以下是一个有效的示例,它将创建此断言,直到进程被终止:

#include <IOKit/pwr_mgt/IOPMLib.h>
#include <unistd.h>

int main()
{
    IOPMAssertionID         neverSleep = 0;

    IOPMAssertionCreateWithName(kIOPMAssertionTypeDisableInflow,
                                kIOPMAssertionLevelOn,
                                CFSTR("disable inflow"),
                                &neverSleep);

    while (1)
    {
        sleep(1);
    }
}

此操作成功运行,并且在进程运行时通过软件断开了电源适配器的连接。

但是,有趣的是,我能够以普通用户的身份运行此代码,而没有root特权,这本来是不会发生的。例如,请注意Apple开源存储库中this file中的评论:

// Disables AC Power Inflow (requires root to initiate)
#define kIOPMAssertionTypeDisableInflow                     CFSTR("DisableInflow")
#define kIOPMInflowDisableAssertion                         kIOPMAssertionTypeDisableInflow

我发现一些代码显然可以执行与充电器的实际通信;可以找到here。来自this file的以下功能似乎特别受关注:

IOReturn 
AppleSmartBatteryManagerUserClient::externalMethod( 
    uint32_t selector, 
    IOExternalMethodArguments * arguments,
    IOExternalMethodDispatch * dispatch __unused, 
    OSObject * target __unused, 
    void * reference __unused )
{
    if (selector >= kNumBattMethods) {
        // Invalid selector
        return kIOReturnBadArgument;
    }

    switch (selector)
    {
        case kSBInflowDisable:
            // 1 scalar in, 1 scalar out
            return this->secureInflowDisable((int)arguments->scalarInput[0],
                                            (int *)&arguments->scalarOutput[0]);
            break;

        // ...
     }

     // ...
}

IOReturn AppleSmartBatteryManagerUserClient::secureInflowDisable(
    int level,
    int *return_code)
{
    int             admin_priv = 0;
    IOReturn        ret = kIOReturnNotPrivileged;

    if( !(level == 0 || level == 1))
    {
        *return_code = kIOReturnBadArgument;
        return kIOReturnSuccess;
    }

    ret = clientHasPrivilege(fOwningTask, kIOClientPrivilegeAdministrator);
    admin_priv = (kIOReturnSuccess == ret);

    if(admin_priv && fOwner) {
        *return_code = fOwner->disableInflow( level );
        return kIOReturnSuccess;
    } else {
        *return_code = kIOReturnNotPrivileged;
        return kIOReturnSuccess;
    }

}

请注意在运行代码之前,如何在secureInflowDisable()中检查root特权。还要注意在同一文件中的该初始化代码,再次需要root特权,如注释中明确指出的那样:

bool AppleSmartBatteryManagerUserClient::initWithTask(task_t owningTask, 
                    void *security_id, UInt32 type, OSDictionary * properties)
{    
    uint32_t            _pid;

     /* 1. Only root processes may open a SmartBatteryManagerUserClient.
      * 2. Attempts to create exclusive UserClients will fail if an
      *     exclusive user client is attached.
      * 3. Non-exclusive clients will not be able to perform transactions
      *     while an exclusive client is attached.
      * 3a. Only battery firmware updaters should bother being exclusive.
      */
    if ( kIOReturnSuccess !=
            clientHasPrivilege(owningTask, kIOClientPrivilegeAdministrator))
    {
        return false;
    }

    // ...
}

same SO question above的代码(问题本身,而不是答案)开始,对于sendSmartBatteryCommand()函数,我编写了一些代码,该代码调用将kSBInflowDisable作为选择器的函数(代码中的变量which)。

与使用断言的代码不同,此代码仅作为root用户工作。如果以普通用户身份运行,IOServiceOpen()会奇怪地返回kIOReturnBadArgument(而不是我所期望的kIOReturnNotPrivileged)。也许这与上面的initWithTask()方法有关。

问题

我需要使用与此智能电池管理器kext不同的选择器进行呼叫。即使这样,由于IOConnectCallMethod()失败,我什至无法进入IOServiceOpen(),大概是因为initWithTask()方法阻止了任何非root用户打开服务。

因此,问题是: IOPMAssertionCreateWithName()如何能够在没有root特权的情况下创建DisableInflow断言?

我唯一想到的是是否存在一个根拥有的进程,该进程将请求转发到该进程,并且该进程执行将IOServiceOpen()和后来的IOConnectCallMethod()称为root的实际工作。

但是,我希望有另一种方法来调用Smart Battery Manager kext,该方法不需要root用户(不涉及IOServiceOpen()调用。)使用IOPMAssertionCreateWithName()本身是在我的应用程序中是不可能的,因为我需要在该kext中调用其他选择器,而不是禁用流入的选择器。

这实际上也可能是一个安全漏洞,一旦收到有关此问题的警报,Apple现在将在将来的版本中修复此漏洞。那太糟糕了,但是可以理解。

尽管在macOS中有可能以root身份运行,但除非绝对必要,否则显然希望避免特权提升。另外,将来我想在iOS下运行相同的代码,据我了解,不可能以root身份运行任何东西(请注意,这是我为个人使用而开发的应用;我了解链接到IOKit消除了在应用商店中发布该应用的任何机会。

0 个答案:

没有答案