kIOReturnNotPermitted от IOServiceOpen, подключающегося к SystemExtension IOService
Я пытаюсь создать клиентское соединение с 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;
}
Редактировать:
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 декста:
<?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 ответа
Обновленный ответ:
В IOServiceDEXTEntitlements
собственность в вашем IOKitPersonality's Info.plist
словарь пользовательских свойств клиента должен быть одним из:
- Полностью отсутствует; это означает: не проверяйте права клиента, кроме основ, перечисленных ниже в моем первоначальном ответе.
- Я думаю, массив массивов строк; у клиента должны быть все права, перечисленные в одном из внутренних массивов. (NB: я не проводил никаких испытаний с этим последним случаем.)
Не-массив или пустой массив IOServiceDEXTEntitlements
средство собственности клиент может не совпадать с правом с одной из внутренних массивов, так как не любые. Поэтому проверка всегда терпит неудачу сkIOReturnNotPermitted
. Вот что происходит с вашим (пустым) строковым значением.
Для получения подробной информации проверьте код в IOUserServer::checkEntitlements()
и откуда он вызван в IOUserServer::serviceNewUserClient()
в IOUserServer.cpp из исходного кода xnu.
Оригинальный ответ:
(Указано до содержания Info.plist
размещается.)
Я не вижу ничего явно неправильного в том, что вы опубликовали, поэтому я подозреваю, что ваша проблема может быть вызвана тем, что вы не опубликовали. На что следует обратить внимание:
- Пользовательское клиентское приложение
com.apple.developer.driverkit.userclient-access
массив должен содержать идентификатор пакета декста. Возможно, еще раз проверьте, действительно ли этот идентификатор равенsc.example.MyUserUSBInterfaceDriver
? (Раньше я потратил больше часа на то, чтобы рвать волосы наkIOReturnNotPermitted
ошибка, когда у меня здесь была опечатка.) - Клиентскому приложению пользователя должно быть разрешено разговаривать с IOKit. Это так по умолчанию, если ваше приложение не находится в песочнице. Предполагая, что опубликованные вами права являются полными, ваше приложение не находится в песочнице, так что это не должно быть проблемой.
- Если словарь, используемый для создания нового пользовательского клиента, содержит
IOServiceDEXTEntitlements
key, приложение пользовательского пространства должно иметь все перечисленные права. (Этот словарь взят из dext info.plist, который вы еще не опубликовали на момент написания.) - Я считаю, что декст и приложение должны быть подписаны с использованием одного и того же идентификатора команды. (Кажется, я помню, что есть право, которое вы можете установить на декст, чтобы обойти это требование.) Возможно, дважды проверьте
TeamIdentifier
с помощьюcodesign -dv path/to/your.dext
а такжеcodesign -dv path/to/your.app
Касательно вашего вопроса - я постараюсь ответить на ваш вопрос отдельно - но я заметил, что вы определяете местонахождение своей службы, перебирая все 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")
)
Хотя это относительно маловероятно, имя службы, полученное черезIORegistryEntryGetName
в опубликованном вами коде теоретически может конфликтовать с другими kexts или dexts, тогда как в идентификаторе пакета не должно быть двусмысленности, а сопоставление класса пользователя полезно, когда ваш драйвер реализует несколько классов.