kIOReturnNotPermitted от IOServiceOpen при подключении к SystemExtension IOService - PullRequest
3 голосов
/ 05 мая 2020

Я пытаюсь создать клиентское соединение с SystemExtension IOService. Я вижу, что мой подкласс IOUserClient создан (вызывается init() и Start(IOService*)), но код возврата из IOServiceOpen возвращает 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>

Права для правописания:

<?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 - это просто макрос, который выполняет 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;
}

Изменить:

Информационный список приложения

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

Информационный список декста:

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

Ответы [ 2 ]

3 голосов
/ 06 мая 2020

Обновленный ответ:

Свойство IOServiceDEXTEntitlements в словаре пользовательских свойств клиента IOKitPersonality Info.plist должно быть одним из:

  1. Полностью отсутствует ; это означает: не проверяйте права клиента, кроме основ, перечисленных ниже в моем исходном ответе.
  2. Я думаю , массив массивов строк ; клиент должен иметь все права, перечисленные в одном внутренних массивов. (NB: я не проводил никаких испытаний с этим последним случаем.)

Свойство без массива или пустого массива IOServiceDEXTEntitlements означает, что клиент не может сопоставить права в один из внутренних массивов, поскольку нет любых . Поэтому проверка всегда терпит неудачу с kIOReturnNotPermitted. Вот что происходит с вашим (пустым) строковым значением.

Для получения подробной информации проверьте код в IOUserServer::checkEntitlements() и место его вызова в IOUserServer::serviceNewUserClient() в IOUserServer. cpp из исходного кода xnu.

Исходный ответ:

(дан до публикации содержимого Info.plist s.)

Я не вижу ничего явно неправильного в том, что вы опубликовали , поэтому я подозреваю, что ваша проблема может быть вызвана тем, что вы не опубликовали . На что следует обратить внимание:

  • Массив com.apple.developer.driverkit.userclient-access пользовательского клиентского приложения должен содержать идентификатор пакета dext. Возможно, еще раз проверьте, действительно ли этот ID равен sc.example.MyUserUSBInterfaceDriver? (Раньше я потратил больше часа на то, чтобы рвать волосы из-за ошибки kIOReturnNotPermitted, когда у меня здесь была опечатка.)
  • Пользовательскому клиентскому приложению должно быть разрешено разговаривать с IOKit. Это так по умолчанию, если ваше приложение не находится в песочнице. Предполагая, что права, которые вы разместили, равны завершено , ваше приложение не изолировано в песочнице, поэтому это не должно быть проблемой.
  • Если словарь, используемый для создания нового пользовательского клиента, содержит IOServiceDEXTEntitlements, приложение пользовательского пространства должно иметь все перечисленные права. (Этот словарь взят из dext info.plist, который вы еще не опубликовали на момент написания.)
  • Я считаю, что dext и приложение должны быть подписаны с использованием одного и того же идентификатора команды. (Кажется, я помню, что есть право, которое вы можете установить в дексте, чтобы обойти это требование.) Возможно, дважды проверьте TeamIdentifier, используя codesign -dv path/to/your.dext и codesign -dv path/to/your.app
1 голос
/ 06 мая 2020

Тангенциально к вашему вопросу - я постараюсь ответить на ваш вопрос отдельно - но я заметил, что вы определяете местонахождение своей службы, перебирая все 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, и все прямые подклассы IOService в dexts на самом деле являются IOUserService объектами в «реальном» (ядре) реестре ввода-вывода.)
  • Со свойством IOUserClass, соответствующим предоставленному driverkit_classname (в вашем случае это будет CFSTR("MyUserUSBInterfaceDriver"))
  • С CFBundleIdentifier, совпадающим с предоставленным. (CFSTR("sc.example.MyUserUSBInterfaceDriver"))

Хотя это относительно маловероятно, служба name , полученная с помощью IORegistryEntryGetName в опубликованном вами коде, теоретически может столкнуться с другими kexts или dexts, в то время как в идентификаторе пакета не должно быть двусмысленности, и сопоставление класса пользователя полезно, когда ваш драйвер реализует несколько классов.

...