kIOReturnNotPermitted 从 IOServiceOpen 连接到 SystemExtension IOService

kIOReturnNotPermitted from IOServiceOpen connecting to SystemExtension IOService

我正在尝试创建到 SystemExtension IOService 的客户端连接。我可以看到我的 IOUserClient 子类已创建(init()Start(IOService*) 被调用),但是 IOServiceOpen returns return 代码 kIOReturnNotPermitted.

我正在从创建激活请求的同一个应用程序调用 IOServiceOpen

发出激活请求/调用 IOServiceOpen 的应用的权利:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>com.apple.developer.driverkit.userclient-access</key>
  <array>
    <string>sc.example.MyUserUSBInterfaceDriver</string>
  </array>
    <key>com.apple.developer.system-extension.install</key>
    <true/>
    <key>com.apple.developer.system-extension.uninstall</key>
    <true/>
</dict>
</plist>

dext 的权利:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>com.apple.developer.driverkit.userclient-access</key>
  <array>
    <string>sc.example.USBApp</string>
  </array>
    <key>com.apple.developer.driverkit</key>
    <true/>
    <key>com.apple.developer.driverkit.transport.usb</key>
    <true/>
</dict>
</plist>

我的用户客户端:

#ifndef MyUserClient_h
#define MyUserClient_h

#include <DriverKit/IOUserClient.iig>

class MyUserClient : public IOUserClient {
public:
  bool init() override;
  kern_return_t Start(IOService* provider) override;
  kern_return_t Stop(IOService* provider) override;
  void free() override;
};

#endif /* MyUserClient_h */
bool MyUserClient::init() {
  LOG();
  if (!super::init()) {
    LOG("super::init() failed");
    return false;
  }
  return true;
}

kern_return_t IMPL(MyUserClient, Start) {
  LOG();
  auto ret = Start(provider, SUPERDISPATCH);
  if (ret != kIOReturnSuccess) {
    LOG("SUPERDISPATCH Start failed, ret: %{public}d", ret);
  }
  return ret;
}

kern_return_t IMPL(MyUserClient, Stop) {
  LOG();
  auto ret = Stop(provider, SUPERDISPATCH);
  if (ret != kIOReturnSuccess) {
    LOG("SUPERDISPATCH Stop failed, ret: %{public}d", ret);
  }
  return ret;
}

void MyUserClient::free() {
  super::free();
  LOG();
}

LOG 只是一个执行 os_log(OS_LOG_DEFAULT, ...

的宏

NewUserClient 实施:

kern_return_t IMPL(MyUserUSBInterfaceDriver, NewUserClient) {
  LOG("%{public}d:", type);

  IOService* client;

  auto ret = Create(this, "UserClientProperties", &client);
  *userClient = OSDynamicCast(IOUserClient, client);
  if (!(*userClient) || ret != kIOReturnSuccess) {
    LOG("Failed to create IOUserClient, %{public}d", ret);
  }
  return ret;
}

连接到系统扩展的代码:

void connectToDext(io_service_t* serviceObject) {
  io_connect_t dataPort;

  kern_return_t kernResult =IOServiceOpen(*serviceObject, mach_task_self(), 123, &dataPort);
  if (kernResult != KERN_SUCCESS) {
    printf("IOServicceOpen failed: %d, %s\n", kernResult, kern_return_t_toCStr(kernResult));
  }
  kernResult = IOServiceClose(dataPort);
  if (kernResult != KERN_SUCCESS) {
    printf("IOServicceClosed failed: %d, %s\n", kernResult, kern_return_t_toCStr(kernResult));
  }
}

int connectToFirstDext() {
      CFMutableDictionaryRef matchingDict;
      matchingDict = IOServiceMatching("IOService");

      if (matchingDict == 0) {
        return -1;
      }

      io_iterator_t iter;
      if (IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &iter) !=
          KERN_SUCCESS) {
        printf("IOServiceGetMatchingServices failed.\n");
        return -1;
      }

      io_service_t device;
      while ((device = IOIteratorNext(iter))) {
        io_name_t deviceName;
        if (IORegistryEntryGetName(device, deviceName) == KERN_SUCCESS) {
          printf("name: %s\n", deviceName);
          if (strcmp(deviceName, "MyUserUSBInterfaceDriver") == 0) {
            printf("Calling connect\n");
            connectToDext(&device);
          }
        }
        IOObjectRelease(device);
      }

      IOObjectRelease(iter);

    return 0;
}

编辑:

Info.plist 个应用

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>BuildMachineOSBuild</key>
    <string>19E287</string>
    <key>CFBundleDevelopmentRegion</key>
    <string>en</string>
    <key>CFBundleExecutable</key>
    <string>USBApp</string>
    <key>CFBundleIdentifier</key>
    <string>sc.example.USBApp</string>
    <key>CFBundleInfoDictionaryVersion</key>
    <string>6.0</string>
    <key>CFBundleName</key>
    <string>USBApp</string>
    <key>CFBundlePackageType</key>
    <string>APPL</string>
    <key>CFBundleShortVersionString</key>
    <string>1.0</string>
    <key>CFBundleSupportedPlatforms</key>
    <array>
        <string>MacOSX</string>
    </array>
    <key>CFBundleVersion</key>
    <string>1</string>
    <key>DTCompiler</key>
    <string>com.apple.compilers.llvm.clang.1_0</string>
    <key>DTPlatformBuild</key>
    <string>11E503a</string>
    <key>DTPlatformVersion</key>
    <string>GM</string>
    <key>DTSDKBuild</key>
    <string>19E258</string>
    <key>DTSDKName</key>
    <string>macosx10.15</string>
    <key>DTXcode</key>
    <string>1141</string>
    <key>DTXcodeBuild</key>
    <string>11E503a</string>
    <key>LSMinimumSystemVersion</key>
    <string>10.15</string>
    <key>NSHumanReadableCopyright</key>
    <string>Copyright © 2020 Example. All rights reserved.</string>
    <key>NSMainNibFile</key>
    <string>MainMenu</string>
    <key>NSPrincipalClass</key>
    <string>NSApplication</string>
    <key>NSSupportsAutomaticTermination</key>
    <true/>
    <key>NSSupportsSuddenTermination</key>
    <true/>
</dict>
</plist>

Info.plist 的 dext:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>BuildMachineOSBuild</key>
    <string>19E287</string>
    <key>CFBundleDevelopmentRegion</key>
    <string>en</string>
    <key>CFBundleExecutable</key>
    <string>sc.example.MyUserUSBInterfaceDriver</string>
    <key>CFBundleIdentifier</key>
    <string>sc.example.MyUserUSBInterfaceDriver</string>
    <key>CFBundleInfoDictionaryVersion</key>
    <string>6.0</string>
    <key>CFBundleName</key>
    <string>sc.example.MyUserUSBInterfaceDriver</string>
    <key>CFBundlePackageType</key>
    <string>DEXT</string>
    <key>CFBundleShortVersionString</key>
    <string>1.0</string>
    <key>CFBundleSupportedPlatforms</key>
    <array>
        <string>MacOSX</string>
    </array>
    <key>CFBundleVersion</key>
    <string>1</string>
    <key>DTCompiler</key>
    <string>com.apple.compilers.llvm.clang.1_0</string>
    <key>DTPlatformBuild</key>
    <string>11E503a</string>
    <key>DTPlatformVersion</key>
    <string>GM</string>
    <key>DTSDKBuild</key>
    <string></string>
    <key>DTSDKName</key>
    <string>driverkit.macosx19.0</string>
    <key>DTXcode</key>
    <string>1141</string>
    <key>DTXcodeBuild</key>
    <string>11E503a</string>
    <key>IOKitPersonalities</key>
    <dict>
        <key>example_device</key>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>sc.example.MyUserUSBInterfaceDriver</string>
            <key>IOClass</key>
            <string>IOUserService</string>
            <key>IOProviderClass</key>
            <string>IOUSBHostInterface</string>
            <key>IOUserClass</key>
            <string>MyUserUSBInterfaceDriver</string>
            <key>IOUserServerName</key>
            <string>sc.example.MyUserUSBInterfaceDriver</string>
            <key>UserClientProperties</key>
            <dict>
                <key>IOClass</key>
                <string>IOUserUserClient</string>
                <key>IOServiceDEXTEntitlements</key>
                <string></string>
                <key>IOUserClass</key>
                <string>MyUserClient</string>
            </dict>
            <key>bConfigurationValue</key>
            <integer>1</integer>
            <key>bInterfaceNumber</key>
            <integer>0</integer>
            <key>idProduct</key>
            <integer>8</integer>
            <key>idVendor</key>
            <integer>1234</integer>
        </dict>     
    </dict>
    <key>OSBundleUsageDescription</key>
    <string>Example user space USB driver</string>
    <key>OSMinimumDriverKitVersion</key>
    <string>19.4</string>
</dict>
</plist>

与您的问题无关 - 我将尝试单独回答您的实际问题 - 但我注意到您正在通过遍历所有 IOService 对象来定位您的服务。你可以通过直接使用 属性 匹配来匹配它,从而更优雅地找到它。我使用辅助函数来生成看起来像这样的匹配字典:

// Creates IOKit matching dictionary for locating driverkit-based service objects
// (Corresponds to kext services' IOServiceMatching())
static CFMutableDictionaryRef user_service_matching(CFStringRef driverkit_classname, CFStringRef driverkit_server_bundle_id) CF_RETURNS_RETAINED
{
    CFMutableDictionaryRef match = IOServiceMatching("IOUserService");
    CFTypeRef match_property_keys[]   = { CFSTR("IOUserClass"), kIOBundleIdentifierKey };
    CFTypeRef match_property_values[] = { driverkit_classname,  driverkit_server_bundle_id };
    CFDictionaryRef match_properties = CFDictionaryCreate(
        kCFAllocatorDefault,
        match_property_keys, match_property_values, 2,
        &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    CFDictionaryAddValue(match, CFSTR(kIOPropertyMatchKey), match_properties);
    CFRelease(match_properties);
    return match;
}

这匹配:

  • IOUserService 类型的对象(这是一个比 IOService 小得多的搜索 space 并且 dexts 中的所有直接 IOService subclasses 实际上是IOUserService "real"(内核)I/O 注册表中的对象。)
  • IOUserClass 属性 与提供的 driverkit_classname 匹配(在您的情况下为 CFSTR("MyUserUSBInterfaceDriver")
  • CFBundleIdentifier 匹配提供的。 (CFSTR("sc.example.MyUserUSBInterfaceDriver"))

虽然相对不太可能,但在您发布的代码中通过 IORegistryEntryGetName 检索到的服务 name 理论上可能会与其他 kexts 或 dexts 发生冲突,而应该包标识符中没有歧义,当您的驱动程序实现多个 classes.

时,匹配用户 class 会很有帮助

更新的答案:

您的 IOKitPersonality Info.plist 的用户客户端 属性 字典中的 IOServiceDEXTEntitlements 属性 应该是以下之一:

  1. 完全缺失;这意味着:不要检查我原始答案中下面列出的基础以外的客户端权利。
  2. 我觉得一个字符串数组的数组;客户端必须具有 all 内部数组 one 中列出的权利。 (注意:我没有对后一种情况进行任何测试。)

非数组或空数组 IOServiceDEXTEntitlements 属性 意味着客户端 无法匹配 one 中的权利内部数组,因为没有 any. 因此检查 总是失败 kIOReturnNotPermitted。这就是您的(空)字符串值所发生的情况。

有关详细信息,请检查 IOUserServer::checkEntitlements() 中的代码以及从 xnu 源代码中 IOUserServer::serviceNewUserClient() 中 IOUserServer.cpp 中调用它的位置。

原回答:

(在 Info.plist 的内容发布之前给出。)

我没有发现您发布的内容有任何明显的错误,所以我怀疑您的问题可能是由您尚未发布的内容引起的。注意事项:

  • 用户客户端应用程序的 com.apple.developer.driverkit.userclient-access 数组必须包含 dext 的包 ID。也许仔细检查这个 ID 真的等于 sc.example.MyUserUSBInterfaceDriver? (我之前因为 kIOReturnNotPermitted 错误在这里拼写错误花了一个多小时。)
  • 必须允许用户客户端应用程序与 IOKit 对话。默认情况下就是这种情况,除非您的应用程序是沙盒的。假设您发布的权利是完整,您的应用程序没有沙盒化,所以这应该不是问题。
  • 如果用于创建新用户客户端的字典包含 IOServiceDEXTEntitlements 键,则用户 space 应用程序必须在此处列出所有权利。 (这本词典来自 dext 的 info.plist,您在撰写本文时尚未发布。)
  • 我认为 dext 和应用程序必须使用相同的团队 ID 进行签名。 (我似乎记得你可以在 dext 上设置一个权利来解决这个要求。)也许使用 codesign -dv path/to/your.dextcodesign -dv path/to/your.app
  • 仔细检查 TeamIdentifier