kIOReturnNotPermitted from IOServiceOpen connecting to SystemExtension IOService

孤街浪徒 提交于 2020-05-15 09:29:06

问题


I am trying to create a client connection to a SystemExtension IOService. I can see that my IOUserClient subclass is created (init() and Start(IOService*) is called), but the return code from IOServiceOpen returns kIOReturnNotPermitted.

I am making the call to IOServiceOpen from the same app that creates the activation request.

Entitlements for app that makes the activation request / call to 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>

Entitlements for the 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>

MyUserClient:

#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 is just a macro that does os_log(OS_LOG_DEFAULT, ...

NewUserClient implementation:

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

Code to connect to system extension:

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

Edit:

Info.plist of app

<?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 of 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>

回答1:


Updated answer:

The IOServiceDEXTEntitlements property in your IOKitPersonality's Info.plist's user client property dictionary should be one of:

  1. Missing entirely; this means: don't check client entitlements beyond basics listed below in my original answer.
  2. I think, an array of arrays of strings; the client must have all the entitlements listed in one of the inner arrays. (NB: I haven't done any testing with this latter case.)

A non-array or empty-array IOServiceDEXTEntitlements property means the client can't match the entitlements in one of the inner arrays, as there aren't any. The check therefore always fails with kIOReturnNotPermitted. This is what's happening with your (empty) string value.

For details, check the code in IOUserServer::checkEntitlements() and where it's called from in IOUserServer::serviceNewUserClient() in IOUserServer.cpp from the xnu source code.

Original answer:

(Given prior to the contents of the Info.plists being posted.)

I don't see anything obviously wrong with what you've posted, so I suspect your problem might be caused by something you haven't posted. Things to watch out for:

  • The user client app's com.apple.developer.driverkit.userclient-access array must contain the dext's bundle ID. Perhaps double-check that this ID really is equal to sc.example.MyUserUSBInterfaceDriver? (I've previously spent over an hour tearing my hair out over the kIOReturnNotPermitted error when I had a typo here.)
  • The user client app must be permitted to talk to IOKit. This is the case by default, unless your app is sandboxed. Assuming the entitlements you've posted are complete, your app isn't sandboxed, so that shouldn't be the problem.
  • If the dictionary used for creating the new user client contains the IOServiceDEXTEntitlements key, the user space app must have all entitlements listed there. (This dictionary comes from the dext's info.plist, which you haven't posted yet at time of writing.)
  • I believe the dext and the app must be signed using the same team ID. (I seem to remember there is an entitlement you can set on the dext to work around this requirement however.) Perhaps double-check the TeamIdentifier using codesign -dv path/to/your.dext and codesign -dv path/to/your.app



回答2:


Tangential to your question - I'll try to answer your actual question separately - but I noticed you're locating your service by iterating over all IOService objects. You can find it much more elegantly by matching it directly using property matching. I use a helper function for generating the matching dictionary that looks something like this:

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

This matches:

  • Objects of type IOUserService (This is a much smaller search space than IOService and all direct IOService subclasses in dexts are actually IOUserService objects in the "real" (kernel) I/O Registry.)
  • With the IOUserClass property matching the provided driverkit_classname (this would be CFSTR("MyUserUSBInterfaceDriver") in your case)
  • With the CFBundleIdentifier matching the provided one. (CFSTR("sc.example.MyUserUSBInterfaceDriver"))

Although relatively unlikely, the service name, as retrieved via IORegistryEntryGetName in the code you posted, could in theory collide with other kexts or dexts, whereas there should be no ambiguity in the bundle identifier, and matching the user class is helpful when your driver implements multiple classes.



来源:https://stackoverflow.com/questions/61613403/kioreturnnotpermitted-from-ioserviceopen-connecting-to-systemextension-ioservice

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!