2

我正在尝试与应用程序中的 dext 进行交互。我能够找到使用的服务,IOServiceOpen并且调用NewUserClient了我的 dext(我可以看到type传递的参数正在日志中输出)。在此之后,我有点失落。在这里阅读有关NewUserClient 的信息 ,我可以看到应该使用它Create来创建一个新的 Service 对象。

这里的讨论部分说字典中的键描述了新服务。propertiesKey

应该将此字典作为顶级条目放置在系统扩展的 plist 文件中,还是应该将字典与 key in 一起放置IOKitPersonalities

我可以将IOServiceDEXTEntitlements密钥保留为空值,以免对连接到系统扩展的应用程序的权利施加任何限制吗?

我的 plist 看起来像这样(MyUserClientProperties在两个地方有 key / dict)。

<?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>CFBundleDevelopmentRegion</key>  
  <string>$(DEVELOPMENT_LANGUAGE)</string>  
  <key>CFBundleExecutable</key>  
  <string>$(EXECUTABLE_NAME)</string>  
  <key>CFBundleIdentifier</key>  
  <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>  
  <key>CFBundleInfoDictionaryVersion</key>  
  <string>6.0</string>  
  <key>CFBundleName</key>  
  <string>$(PRODUCT_NAME)</string>  
  <key>CFBundlePackageType</key>  
  <string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>  
  <key>CFBundleShortVersionString</key>  
  <string>1.0</string>  
  <key>CFBundleVersion</key>  
  <string>1</string>  
  <key>MyUserClientProperties</key>  
       <dict>  
           <key>IOClass</key>  
           <string>MyUserClient</string>  
           <key>IOUserClass</key>  
           <string>MyUserUSBInterfaceDriver</string>  
           <key>IOServiceDEXTEntitlements</key>  
           <string></string>  
       </dict>  
  <key>IOKitPersonalities</key>  
  <dict>  
  <key>example_device</key>  
  <dict>  
      <key>MyUserClientProperties</key>  
           <dict>  
               <key>IOClass</key>  
               <string>MyUserClient</string>  
               <key>IOUserClass</key>  
               <string>MyUserUSBInterfaceDriver</string>  
               <key>IOServiceDEXTEntitlements</key>  
               <string></string>  
           </dict>  
  <key>CFBundleIdentifier</key>  
  <string>$(PRODUCT_BUNDLE_IDENTIFIER)</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>bConfigurationValue</key>  
      <integer>0x1</integer>  
      <key>bInterfaceNumber</key>  
      <integer>0x0</integer>  
      <key>idVendor</key>  
      <integer>0x123</integer>  
      <key>idProduct</key>  
      <integer>0x08</integer>  
  </dict>  
  </dict>  
    <key>OSBundleUsageDescription</key>  
    <string>Example user space USB driver</string>  
</dict>  
</plist>  

我是否需要SUPERDISPATCH作为最后一个参数传递给Create?

来自“OSX 和 iOS 内核编程”第 5 章第 81 页:

I/O Kit 设计的独创性在于用户客户端对象本身就是一个驱动程序对象:IOUserClient 类继承自 IOService,并且与任何其他 IOService 实例一样,每个用户客户端都有一个提供者类,对于用户客户端而言,它是应用程序正在控制的驱动程序的实例。

虽然上面可能只对 kext 正确(?)我会假设事情的工作方式与 dext 相同,

来自Create文档:使用 kIOUserClassKey 键指定您希望系统实例化的自定义 IOService 子类的名称。

为什么IOService需要实例化另一个类?这门课的目的是什么?是继承自我的类的提供者IOUserClient吗?如果是这样,我怎样才能使我的驱动程序实例(实现的那个NewUserClient)提供程序?

来自Create文档:使用kIOClassKey指定自定义IOUserClient子类的名称以返回给您的服务的客户端。

将创建并分配给 的第三个参数的类的类型是Create什么?如果是这样,那是我应该分配IOUserClient*指针的那个,它被传递给NewUserClient

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

  IOPropertyName propertiesKey = "MyUserClientProperties";  

  IOService* client;  

  auto ret = Create(this, propertiesKey, &client, SUPERDISPATCH);  
  // Need to do more things here...  
  return ret;  
}  

无论我尝试什么,我总是得到一个断言,但我看不出是什么原因造成的。

3   com.apple.DriverKit            0x0000000102f2b24b __assert_rtn + 102  
4   com.apple.DriverKit            0x0000000102f2c20a IOService::Create_Impl(IOService*, char const*, IOService**) (.cold.2) + 35  
5   com.apple.DriverKit            0x0000000102f1766b IOService::Create_Impl(IOService*, char const*, IOService**) + 91  
6   com.apple.DriverKit            0x0000000102f2668f IOService::Create_Invoke(IORPC, OSMetaClassBase*, int (*)(OSMetaClassBase*, IOService*, char const*, IOService**)) + 135  
7   com.apple.DriverKit            0x0000000102f276d7 IOService::Create(IOService*, char const*, IOService**, int (*)(OSMetaClassBase*, IORPC)) + 267  
8   sc.example.MyUserUSBInterfaceDriver 0x0000000102ee0c89 MyUserUSBInterfaceDriver::NewUserClient_Impl(unsigned int, IOUserClient**) + 313 (MyUserUSBInterfaceDriver.cpp:155)
4

1 回答 1

3

正如 WWDC 关于 DriverKit 的演示试图假装的那样,DriverKit 的世界观与内核的非常不同,您需要了解一些实现细节,因为抽象非常容易泄漏。

正如您可能已经发现的那样,IOService在 DriverKit 驱动程序中看起来像一个对象实际上是IOUserServiceI/O 注册表的内核(和用户空间)视图中的一个对象。差距是通过 DriverKit 的 IPC 机制来弥补的。

为了创建一个新的用户客户端,您需要一个(内核) IOUserClient子类的实例,它由您的(dext)IOUserClient子类支持。这个内核类实际上是IOUserUserClient. (是的,真的。)正如您所发现的,文档并不清楚您如何处理此问题。我发现查看源代码方面的可用内容很有帮助 - 调用的内核方面在此处的函数NewUserClient 中实现IOUserServer::serviceNewUserClient()

您会立即注意到的一件事是,如果IOServiceDEXTEntitlements缺少该属性,这不会阻止代码成功:

            prop = userUC->copyProperty(gIOServiceDEXTEntitlementsKey);
            ok = checkEntitlements(entitlements, prop, NULL, NULL);

并在checkEntitlements

    if (!prop) {
        return true;
    }

这是个好消息,因为这意味着我们暂时不需要担心它,而可以简单地把它关掉。

Next, it turns out that the propertiesKey refers to a property on the provider IOUserService kernel object. You can't set those properties from inside the dext's code, so the only way to provide them is from the IOKit matching personality dictionary.

You can name this property however you want, but:

  • Its value must be a dictionary.
  • It must contain the "IOClass" key-value pair, specifying the kernel class to instantiate as a string - in your case, "IOUserUserClient"
  • It must contain the "IOUserClass" key-value pair. This specifies the dext class to instantiate, again as a string. In your case, that looks like MyUserClient.

Putting it together:

  <key>IOKitPersonalities</key>  
  <dict>
    <key>example_device</key>  
    <dict>  
      <key>MyUserClientProperties</key>
      <dict>
        <key>IOUserClass</key>
        <string>MyUserClient</string>
        <key>IOClass</key>
        <string>IOUserUserClient</string>
      </dict>
      <key>CFBundleIdentifier</key>
      <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
      …
    </dict>
  </dict>
  …

Then, from your NewUserClient function, call:

    IOService* client = nullptr;
    kern_return_t ret = this->Create(this, "MyUserClient", &client);

I don't believe SUPERDISPATCH is needed here, as you presumably don't override the Create method in your class, so you super-implementation is inherited anyway.

Then do your error checking, any other initialisation, preparation, etc. you might need, and finally:

    *userClient = client;
    return kIOReturnSuccess;
于 2020-05-03T10:56:25.560 回答