防止 IOKit 驱动程序在 "kextunload" 中关闭,除非某些客户端保持连接
Prevent IOKit driver down in "kextunload" unless some clients remains connected
我有 IOKit 基础 Driver/Deamons 项目,具有一对多关系(意味着多个客户端连接到单个驱动程序)。
核心驱动是一个派生自IOService
的IOKit对象,也是派生自IOUserClient
的驱动客户端提供者。这些是用户-space 客户的代理(每个用户-space 客户一个)
我的目标是防止驱动程序在具有 root 权限的 kextunload
命令的情况下卸载,这样只有当最后一个客户端断开连接时(进程终止或调用 IOServiceClose
),驱动程序才会自动关闭(无需手动 kextunload
)
为了检查我需要执行哪些 IOKit 命令 disable/postphone,我用相关的打印消息包装了 basid IOService
回调,并观察了 [=52= 场景中的日志] kextunload
其中连接了 2 个客户端:
kernel: (driver) virtual bool com_osxkernel_driver::terminate(IOOptionBits)
kernel: (driver) virtual bool com_osxkernel_driverClient::terminate(IOOptionBits)
kernel: (driver) virtual bool com_osxkernel_driverClient::terminate(IOOptionBits)
kernel: (driver) virtual void com_osxkernel_driverClient::stop(IOService *)
kernel: (driver) virtual void com_osxkernel_driverClient::stop(IOService *)
kernel: (driver) virtual void com_osxkernel_driver::stop(IOService *)
--
似乎即使我从每个 IOUserClient
的提供者那里获取参考,并在 IOUserClient::clientClose
上发布这些参考
, kextunload
命令仍然成功。
我发现实现我的目标的唯一方法是推迟 ::terminate
命令并从 ::clientClose
明确调用它。
所以我删除了对 IOService::terminate
的调用,而是从 IOUserClient::clientClose()
调用它。
这里是相关代码:
IOReturn com_osxkernel_driverClient::clientClose()
{
myProvider->release();
return super::terminate(kIOServiceSynchronous) ? kIOReturnSuccess : kIOReturnError;
}
bool com_osxkernel_driverClient::terminate(IOOptionBits options) {
os_log_info(g_logger,"%s", __PRETTY_FUNCTION__);
return true;
}
我想知道是否有任何更简单的方法来阻止 kextunload
成功并控制驱动程序卸载的时间。
感谢
如果您查看 the kextunload
source code,您会看到它向下调用 IOCatalogueTerminate()
。在内核中,这最终进入 IOCatalogue::_terminateDrivers()
函数。 (IOCatalogue.cpp 在 xnu 源代码中)你会看到以下是 运行 属于正在卸载的 kext 的每个 IOKit class 实例:
if ( !service->terminate(kIOServiceRequired|kIOServiceSynchronous) )
{
ret = kIOReturnUnsupported;
break;
}
这表明停止您的 kext 的 IORegistry 条目的唯一方法确实是 returning false from terminate()
.
像这样硬阻止它是否是个好主意当然完全是另一个问题。我建议您仅在卸载会危及操作系统的稳定性时才这样做。考虑到 kextunload
需要 root 权限,因此在大多数情况下,最好在用户空间代码中简单地处理服务和用户客户端的终止。
如果您从 terminate()
做 return 错误,您还需要注意不要出于正当理由阻止终止。 (例如,如果它是一个设备驱动程序,则匹配您的驱动程序的 nub,例如 IOUSBInterface
可能会尝试 terminate()
如果设备是热拔出的,您的驱动程序实例。)
我有 IOKit 基础 Driver/Deamons 项目,具有一对多关系(意味着多个客户端连接到单个驱动程序)。
核心驱动是一个派生自IOService
的IOKit对象,也是派生自IOUserClient
的驱动客户端提供者。这些是用户-space 客户的代理(每个用户-space 客户一个)
我的目标是防止驱动程序在具有 root 权限的 kextunload
命令的情况下卸载,这样只有当最后一个客户端断开连接时(进程终止或调用 IOServiceClose
),驱动程序才会自动关闭(无需手动 kextunload
)
为了检查我需要执行哪些 IOKit 命令 disable/postphone,我用相关的打印消息包装了 basid IOService
回调,并观察了 [=52= 场景中的日志] kextunload
其中连接了 2 个客户端:
kernel: (driver) virtual bool com_osxkernel_driver::terminate(IOOptionBits)
kernel: (driver) virtual bool com_osxkernel_driverClient::terminate(IOOptionBits)
kernel: (driver) virtual bool com_osxkernel_driverClient::terminate(IOOptionBits)
kernel: (driver) virtual void com_osxkernel_driverClient::stop(IOService *)
kernel: (driver) virtual void com_osxkernel_driverClient::stop(IOService *)
kernel: (driver) virtual void com_osxkernel_driver::stop(IOService *)
--
似乎即使我从每个 IOUserClient
的提供者那里获取参考,并在 IOUserClient::clientClose
上发布这些参考
, kextunload
命令仍然成功。
我发现实现我的目标的唯一方法是推迟 ::terminate
命令并从 ::clientClose
明确调用它。
所以我删除了对 IOService::terminate
的调用,而是从 IOUserClient::clientClose()
调用它。
这里是相关代码:
IOReturn com_osxkernel_driverClient::clientClose()
{
myProvider->release();
return super::terminate(kIOServiceSynchronous) ? kIOReturnSuccess : kIOReturnError;
}
bool com_osxkernel_driverClient::terminate(IOOptionBits options) {
os_log_info(g_logger,"%s", __PRETTY_FUNCTION__);
return true;
}
我想知道是否有任何更简单的方法来阻止 kextunload
成功并控制驱动程序卸载的时间。
感谢
如果您查看 the kextunload
source code,您会看到它向下调用 IOCatalogueTerminate()
。在内核中,这最终进入 IOCatalogue::_terminateDrivers()
函数。 (IOCatalogue.cpp 在 xnu 源代码中)你会看到以下是 运行 属于正在卸载的 kext 的每个 IOKit class 实例:
if ( !service->terminate(kIOServiceRequired|kIOServiceSynchronous) )
{
ret = kIOReturnUnsupported;
break;
}
这表明停止您的 kext 的 IORegistry 条目的唯一方法确实是 returning false from terminate()
.
像这样硬阻止它是否是个好主意当然完全是另一个问题。我建议您仅在卸载会危及操作系统的稳定性时才这样做。考虑到 kextunload
需要 root 权限,因此在大多数情况下,最好在用户空间代码中简单地处理服务和用户客户端的终止。
如果您从 terminate()
做 return 错误,您还需要注意不要出于正当理由阻止终止。 (例如,如果它是一个设备驱动程序,则匹配您的驱动程序的 nub,例如 IOUSBInterface
可能会尝试 terminate()
如果设备是热拔出的,您的驱动程序实例。)